fix(ivy): walk declaration views in listener (#25228)

PR Close #25228
This commit is contained in:
Kara Erickson
2018-07-30 19:43:56 -07:00
committed by Igor Minar
parent 64516da6b0
commit c8a4fb1faf
13 changed files with 323 additions and 107 deletions

View File

@ -70,6 +70,8 @@ export {
f7 as ɵf7,
f8 as ɵf8,
fV as ɵfV,
gV as ɵgV,
rV as ɵrV,
cR as ɵcR,
cr as ɵcr,
qR as ɵqR,

View File

@ -7,7 +7,7 @@
*/
import {assertEqual, assertLessThan} from './assert';
import {NO_CHANGE, bindingUpdated, bindingUpdated2, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, getViewData, load, resetApplicationState} from './instructions';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetApplicationState} from './instructions';
import {RENDER_PARENT} from './interfaces/container';
import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node';
import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view';
@ -250,7 +250,7 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) {
ngDevMode.rendererMoveNode++;
}
const viewData = getViewData();
const viewData = _getViewData();
appendChild(parentNode, node.native || null, viewData);
@ -291,7 +291,7 @@ function appendI18nNode(node: LNode, parentNode: LNode, previousNode: LNode) {
* @param instructions The list of instructions to apply on the current view.
*/
export function i18nApply(startIndex: number, instructions: I18nInstruction[]): void {
const viewData = getViewData();
const viewData = _getViewData();
if (ngDevMode) {
assertEqual(viewData[BINDING_INDEX], -1, 'i18nApply should be called before any binding');
}

View File

@ -63,6 +63,9 @@ export {
elementStyleProp as sp,
elementStylingApply as sa,
getCurrentView as gV,
restoreView as rV,
listener as L,
store as st,
load as ld,

View File

@ -22,7 +22,7 @@ import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LEleme
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
import {LQueries} from './interfaces/query';
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
@ -108,11 +108,40 @@ export function getCurrentSanitizer(): Sanitizer|null {
return viewData && viewData[SANITIZER];
}
export function getViewData(): LViewData {
/**
* Returns the current OpaqueViewState instance.
*
* Used in conjunction with the restoreView() instruction to save a snapshot
* of the current view and restore it when listeners are invoked. This allows
* walking the declaration view tree in listeners to get vars from parent views.
*/
export function getCurrentView(): OpaqueViewState {
return (viewData as any) as OpaqueViewState;
}
/**
* Internal function that returns the current LViewData instance.
*
* The getCurrentView() instruction should be used for anything public.
*/
export function _getViewData(): LViewData {
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
return viewData;
}
/**
* Restores `contextViewData` to the given OpaqueViewState instance.
*
* Used in conjunction with the getCurrentView() instruction to save a snapshot
* of the current view and restore it when listeners are invoked. This allows
* walking the declaration view tree in listeners to get vars from parent views.
*
* @param viewToRestore The LViewData instance to restore.
*/
export function restoreView(viewToRestore: OpaqueViewState) {
contextViewData = (viewToRestore as any) as LViewData;
}
/** Used to set the parent property when nodes are created. */
let previousOrParentNode: LNode;
@ -583,9 +612,9 @@ export function renderEmbeddedTemplate<T>(
* @param level The relative level of the view from which to grab context compared to contextVewData
* @returns context
*/
export function nextContext(level: number = 1): any {
export function nextContext<T = any>(level: number = 1): T {
contextViewData = walkUpViews(level, contextViewData !);
return contextViewData[CONTEXT];
return contextViewData[CONTEXT] as T;
}
export function renderComponentOrTemplate<T>(

View File

@ -40,6 +40,14 @@ export const CONTAINER_INDEX = 14;
export const CONTENT_QUERIES = 15;
export const DECLARATION_VIEW = 16;
// This interface replaces the real LViewData interface if it is an arg or a
// return value of a public instruction. This ensures we don't need to expose
// the actual interface, which should be kept private.
export interface OpaqueViewState {
'__brand__': 'Brand for OpaqueViewState that nothing will match';
}
/**
* `LViewData` stores all of the information needed to process the instructions as
* they are invoked from the template. Each embedded view and component view has its

View File

@ -57,6 +57,8 @@ export const angularCoreEnv: {[name: string]: Function} = {
'ɵf7': r3.f7,
'ɵf8': r3.f8,
'ɵfV': r3.fV,
'ɵgV': r3.gV,
'ɵrV': r3.rV,
'ɵi1': r3.i1,
'ɵi2': r3.i2,
'ɵi3': r3.i3,