refactor(ivy): move directives into separate array (#22918)

PR Close #22918
This commit is contained in:
Kara Erickson 2018-03-21 15:10:34 -07:00 committed by Matias Niemelä
parent 34981063ec
commit 49396ca2ae
28 changed files with 544 additions and 441 deletions

View File

@ -30,6 +30,7 @@ export {
T as ɵT,
V as ɵV,
Q as ɵQ,
d as ɵd,
P as ɵP,
b as ɵb,
i1 as ɵi1,
@ -79,9 +80,9 @@ export {
bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript,
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl,
sanitizeHtml as ɵsanitizeHtml,
sanitizeStyle as ɵsanitizeStyle,
sanitizeUrl as ɵsanitizeUrl,
sanitizeResourceUrl as ɵsanitizeResourceUrl,
sanitizeHtml as ɵsanitizeHtml,
sanitizeStyle as ɵsanitizeStyle,
sanitizeUrl as ɵsanitizeUrl,
sanitizeResourceUrl as ɵsanitizeResourceUrl,
} from './sanitization/sanitization';
// clang-format on

View File

@ -140,9 +140,9 @@ export function renderComponent<T>(
try {
// Create element node at index 0 in data array
elementNode = hostElement(hostNode, componentDef);
// Create directive instance with factory() and store at index 1 in data array (el is 0)
// Create directive instance with factory() and store at index 0 in directives array
component = rootContext.component =
baseDirectiveCreate(1, componentDef.factory(), componentDef) as T;
baseDirectiveCreate(0, componentDef.factory(), componentDef) as T;
initChangeDetectorIfExisting(elementNode.nodeInjector, component);
} finally {
// We must not use leaveView here because it will set creationMode to false too early,
@ -172,8 +172,8 @@ export function renderComponent<T>(
export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): void {
const elementNode = _getComponentHostLElementNode(component);
// Root component is always created at dir index 1, after host element at 0
queueInitHooks(1, def.onInit, def.doCheck, elementNode.view.tView);
// Root component is always created at dir index 0
queueInitHooks(0, def.onInit, def.doCheck, elementNode.view.tView);
queueLifecycleHooks(elementNode.tNode !.flags, elementNode.view);
}

View File

@ -316,10 +316,11 @@ function getOrCreateHostChangeDetector(currentNode: LViewNode | LElementNode):
const hostInjector = hostNode.nodeInjector;
const existingRef = hostInjector && hostInjector.changeDetectorRef;
return existingRef ? existingRef :
createViewRef(
hostNode.data as LView,
hostNode.view.data[hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT]);
return existingRef ?
existingRef :
createViewRef(
hostNode.data as LView,
hostNode.view.directives ![hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT]);
}
/**
@ -394,13 +395,13 @@ export function getOrCreateInjectable<T>(
// nothing to the "left" of it so it doesn't need a mask.
const start = flags >> TNodeFlags.INDX_SHIFT;
const tData = node.view.tView.data;
const defs = node.view.tView.directives !;
for (let i = start, ii = start + size; i < ii; i++) {
// Get the definition for the directive at this index and, if it is injectable (diPublic),
// and matches the given token, return the directive instance.
const directiveDef = tData[i] as DirectiveDef<any>;
const directiveDef = defs[i] as DirectiveDef<any>;
if (directiveDef.diPublic && directiveDef.type == token) {
return getDirectiveInstance(node.view.data[i]);
return getDirectiveInstance(node.view.directives ![i]);
}
}
}
@ -530,7 +531,7 @@ export const QUERY_READ_FROM_NODE =
(new ReadFromInjectorFn<any>((injector: LInjector, node: LNode, directiveIdx: number) => {
ngDevMode && assertNodeOfPossibleTypes(node, LNodeType.Container, LNodeType.Element);
if (directiveIdx > -1) {
return node.view.data[directiveIdx];
return node.view.directives ![directiveIdx];
} else if (node.type === LNodeType.Element) {
return getOrCreateElementRef(injector);
} else if (node.type === LNodeType.Container) {

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {assertEqual} from './assert';
import {DirectiveDef} from './interfaces/definition';
import {TNodeFlags} from './interfaces/node';
import {HookData, LView, LifecycleStage, TView} from './interfaces/view';
@ -24,15 +25,15 @@ import {HookData, LView, LifecycleStage, TView} from './interfaces/view';
*/
export function queueInitHooks(
index: number, onInit: (() => void) | null, doCheck: (() => void) | null, tView: TView): void {
if (tView.firstTemplatePass === true) {
if (onInit != null) {
(tView.initHooks || (tView.initHooks = [])).push(index, onInit);
}
ngDevMode &&
assertEqual(tView.firstTemplatePass, true, 'Should only be called on first template pass');
if (onInit) {
(tView.initHooks || (tView.initHooks = [])).push(index, onInit);
}
if (doCheck != null) {
(tView.initHooks || (tView.initHooks = [])).push(index, doCheck);
(tView.checkHooks || (tView.checkHooks = [])).push(index, doCheck);
}
if (doCheck) {
(tView.initHooks || (tView.initHooks = [])).push(index, doCheck);
(tView.checkHooks || (tView.checkHooks = [])).push(index, doCheck);
}
}
@ -50,7 +51,7 @@ export function queueLifecycleHooks(flags: number, currentView: LView): void {
// directiveCreate) so we can preserve the current hook order. Content, view, and destroy
// hooks for projected components and directives must be called *before* their hosts.
for (let i = start; i < end; i++) {
const def = (tView.data[i] as DirectiveDef<any>);
const def = (tView.directives ![i] as DirectiveDef<any>);
queueContentHooks(def, tView, i);
queueViewHooks(def, tView, i);
queueDestroyHooks(def, tView, i);
@ -60,11 +61,11 @@ export function queueLifecycleHooks(flags: number, currentView: LView): void {
/** Queues afterContentInit and afterContentChecked hooks on TView */
function queueContentHooks(def: DirectiveDef<any>, tView: TView, i: number): void {
if (def.afterContentInit != null) {
if (def.afterContentInit) {
(tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentInit);
}
if (def.afterContentChecked != null) {
if (def.afterContentChecked) {
(tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentChecked);
(tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, def.afterContentChecked);
}
@ -72,11 +73,11 @@ function queueContentHooks(def: DirectiveDef<any>, tView: TView, i: number): voi
/** Queues afterViewInit and afterViewChecked hooks on TView */
function queueViewHooks(def: DirectiveDef<any>, tView: TView, i: number): void {
if (def.afterViewInit != null) {
if (def.afterViewInit) {
(tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewInit);
}
if (def.afterViewChecked != null) {
if (def.afterViewChecked) {
(tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewChecked);
(tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, def.afterViewChecked);
}
@ -96,7 +97,7 @@ function queueDestroyHooks(def: DirectiveDef<any>, tView: TView, i: number): voi
*/
export function executeInitHooks(currentView: LView, tView: TView, creationMode: boolean): void {
if (currentView.lifecycleStage === LifecycleStage.INIT) {
executeHooks(currentView.data, tView.initHooks, tView.checkHooks, creationMode);
executeHooks(currentView.directives !, tView.initHooks, tView.checkHooks, creationMode);
currentView.lifecycleStage = LifecycleStage.AFTER_INIT;
}
}
@ -110,7 +111,7 @@ export function executeHooks(
data: any[], allHooks: HookData | null, checkHooks: HookData | null,
creationMode: boolean): void {
const hooksToCall = creationMode ? allHooks : checkHooks;
if (hooksToCall != null) {
if (hooksToCall) {
callHooks(data, hooksToCall);
}
}

View File

@ -56,6 +56,7 @@ export {
listener as L,
store as st,
load as ld,
loadDirective as d,
projection as P,
projectionDef as pD,

View File

@ -48,7 +48,7 @@ export type Sanitizer = (value: any) => string;
*
* Saved here to avoid re-instantiating an array on every change detection run.
*/
const rootDirectiveIndices = [1, 0];
const rootDirectiveIndices = [0, 0];
/**
@ -95,9 +95,8 @@ let isParent: boolean;
* Static data that corresponds to the instance-specific data array on an LView.
*
* Each node's static data is stored in tData at the same index that it's stored
* in the data array. Each directive's definition is stored here at the same index
* as its directive instance in the data array. Any nodes that do not have static
* data store a null value in tData to avoid a sparse array.
* in the data array. Any nodes that do not have static data store a null value in
* tData to avoid a sparse array.
*/
let tData: TData;
@ -134,6 +133,14 @@ export function getCreationMode(): boolean {
*/
let data: any[];
/**
* An array of directive instances in the current view.
*
* These must be stored separately from LNodes because their presence is
* unknown at compile-time and thus space cannot be reserved in data[].
*/
let directives: any[]|null;
/**
* Points to the next binding index to read or write to.
*/
@ -188,6 +195,7 @@ const enum BindingDirection {
export function enterView(newView: LView, host: LElementNode | LViewNode | null): LView {
const oldView = currentView;
data = newView && newView.data;
directives = newView && newView.directives;
bindingIndex = newView && newView.bindingStartIndex || 0;
tData = newView && newView.tView.data;
creationMode = newView && (newView.flags & LViewFlags.CreationMode) === LViewFlags.CreationMode;
@ -214,8 +222,7 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null)
export function leaveView(newView: LView): void {
if (!checkNoChangesMode) {
executeHooks(
currentView.data, currentView.tView.viewHooks, currentView.tView.viewCheckHooks,
creationMode);
directives !, currentView.tView.viewHooks, currentView.tView.viewCheckHooks, creationMode);
}
// Views should be clean and in update mode after being checked, so these bits are cleared
currentView.flags &= ~(LViewFlags.CreationMode | LViewFlags.Dirty);
@ -229,7 +236,6 @@ function refreshDirectives() {
const tView = currentView.tView;
// This needs to be set before children are processed to support recursive components
// so to refresh the component, refresh() needs to be called with (1, 0)
tView.firstTemplatePass = firstTemplatePass = false;
setHostBindings(tView.hostBindings);
@ -239,11 +245,11 @@ function refreshDirectives() {
/** Sets the host bindings for the current view. */
function setHostBindings(bindings: number[] | null): void {
if (bindings != null) {
const defs = currentView.tView.directives !;
for (let i = 0; i < bindings.length; i += 2) {
const dirIndex = bindings[i];
const elementIndex = bindings[i | 1];
const def = tData[dirIndex] as DirectiveDef<any>;
def.hostBindings && def.hostBindings(dirIndex, elementIndex);
const def = defs[dirIndex] as DirectiveDef<any>;
def.hostBindings && def.hostBindings(dirIndex, bindings[i | 1]);
}
}
}
@ -251,8 +257,8 @@ function setHostBindings(bindings: number[] | null): void {
/** Refreshes child components in the current view. */
function refreshChildComponents(components: number[] | null): void {
if (components != null) {
for (let i = 0; i < components.length; i++) {
componentRefresh(components[i] + 1, components[i]);
for (let i = 0; i < components.length; i += 2) {
componentRefresh(components[i], components[i | 1]);
}
}
}
@ -261,7 +267,7 @@ function executeInitAndContentHooks(): void {
if (!checkNoChangesMode) {
const tView = currentView.tView;
executeInitHooks(currentView, tView, creationMode);
executeHooks(currentView.data, tView.contentHooks, tView.contentCheckHooks, creationMode);
executeHooks(directives !, tView.contentHooks, tView.contentCheckHooks, creationMode);
}
}
@ -274,6 +280,7 @@ export function createLView(
flags: flags | LViewFlags.CreationMode | LViewFlags.Attached,
node: null !, // until we initialize it in createNode.
data: [],
directives: null,
tView: tView,
cleanup: null,
renderer: renderer,
@ -451,9 +458,10 @@ export function renderComponentOrTemplate<T>(
} else {
executeInitAndContentHooks();
// Element was stored at 0 and directive was stored at 1 in renderComponent
// Element was stored at 0 in data and directive was stored at 0 in directives
// in renderComponent()
setHostBindings(rootDirectiveIndices);
componentRefresh(1, 0);
componentRefresh(0, 0);
}
} finally {
if (rendererFactory.end) {
@ -497,10 +505,14 @@ export function elementStart(
let hostComponentDef: ComponentDef<any>|null = null;
let name = nameOrComponentType as string;
let directiveIndex = getNextDirectiveIndex(index);
if (isHostElement) {
hostComponentDef = firstTemplatePass ?
(nameOrComponentType as ComponentType<any>).ngComponentDef :
tData[index + 1] as ComponentDef<any>;
currentView.tView.directives ![directiveIndex] as ComponentDef<any>;
name = hostComponentDef !.tag;
}
@ -524,8 +536,8 @@ export function elementStart(
node = createLNode(index, LNodeType.Element, native, componentView);
if (node.tNode == null) {
const localNames: (string | number)[]|null =
findMatchingLocalNames(hostComponentDef, localRefs, isHostElement ? index + 1 : -1, '');
const localNames: (string | number)[]|null = findMatchingLocalNames(
hostComponentDef, localRefs, isHostElement ? directiveIndex : -1, '');
ngDevMode && assertDataInRange(index - 1);
node.tNode = tData[index] = createTNode(name, attrs || null, null, localNames);
}
@ -533,37 +545,34 @@ export function elementStart(
if (attrs) setUpAttributes(native, attrs);
appendChild(node.parent !, native, currentView);
const elementIndex = index;
if (hostComponentDef) {
// TODO(mhevery): This assumes that the directives come in correct order, which
// is not guaranteed. Must be refactored to take it into account.
const instance = hostComponentDef.factory();
directiveCreate(++index, instance, hostComponentDef, null);
directiveCreate(directiveIndex, index, instance, hostComponentDef, null);
initChangeDetectorIfExisting(node.nodeInjector, instance);
queueComponentIndexForCheck(elementIndex);
if (hostComponentDef.hostBindings) queueHostBindingForCheck(index, elementIndex);
queueComponentIndexForCheck(directiveIndex, index);
directiveIndex++;
}
hack_declareDirectives(index, elementIndex, directiveTypes, localRefs);
hack_declareDirectives(directiveIndex, index, directiveTypes, localRefs);
}
}
return native;
}
/** Stores index of component's host element so it will be queued for view refresh during CD. */
function queueComponentIndexForCheck(elIndex: number): void {
function queueComponentIndexForCheck(dirIndex: number, elIndex: number): void {
if (firstTemplatePass) {
(currentView.tView.components || (currentView.tView.components = [])).push(elIndex);
(currentView.tView.components || (currentView.tView.components = [])).push(dirIndex, elIndex);
}
}
/** Stores index of directive and host element so it will be queued for binding refresh during CD.
*/
function queueHostBindingForCheck(dirIndex: number, elIndex: number): void {
if (firstTemplatePass) {
(currentView.tView.hostBindings || (currentView.tView.hostBindings = [
])).push(dirIndex, elIndex);
}
ngDevMode &&
assertEqual(firstTemplatePass, true, 'Should only be called in first template pass.');
(currentView.tView.hostBindings || (currentView.tView.hostBindings = [])).push(dirIndex, elIndex);
}
/** Sets the context for a ChangeDetectorRef to the given instance. */
@ -578,20 +587,19 @@ export function initChangeDetectorIfExisting(injector: LInjector | null, instanc
* come in the correct order for DI.
*/
function hack_declareDirectives(
index: number, elIndex: number, directiveTypes: DirectiveType<any>[] | null | undefined,
index: number, elementIndex: number, directiveTypes: DirectiveType<any>[] | null | undefined,
localRefs: string[] | null | undefined, ) {
if (directiveTypes) {
const defs = currentView.tView.directives !;
// TODO(mhevery): This assumes that the directives come in correct order, which
// is not guaranteed. Must be refactored to take it into account.
for (let i = 0; i < directiveTypes.length; i++) {
index++;
const directiveType = directiveTypes[i];
const directiveDef =
firstTemplatePass ? directiveType.ngDirectiveDef : tData[index] as DirectiveDef<any>;
const localNames =
firstTemplatePass ? findMatchingLocalNames(directiveDef, localRefs, index) : null;
directiveCreate(index, directiveDef.factory(), directiveDef, localNames);
if (directiveDef.hostBindings) queueHostBindingForCheck(index, elIndex);
firstTemplatePass ? directiveType.ngDirectiveDef : defs[index] as DirectiveDef<any>;
directiveCreate(index, elementIndex, directiveDef.factory(), directiveDef, localRefs);
index++;
}
}
}
@ -633,6 +641,7 @@ function getOrCreateTView(template: ComponentTemplate<any>): TView {
export function createTView(): TView {
return {
data: [],
directives: null,
firstTemplatePass: true,
initHooks: null,
checkHooks: null,
@ -641,6 +650,7 @@ export function createTView(): TView {
viewHooks: null,
viewCheckHooks: null,
destroyHooks: null,
pipeDestroyHooks: null,
hostBindings: null,
components: null
};
@ -758,8 +768,8 @@ export function listener(
*/
function createOutput(outputs: PropertyAliasValue, listener: Function): void {
for (let i = 0; i < outputs.length; i += 2) {
ngDevMode && assertDataInRange(outputs[i] as number);
const subscription = data[outputs[i] as number][outputs[i | 1]].subscribe(listener);
ngDevMode && assertDataInRange(outputs[i] as number, directives !);
const subscription = directives ![outputs[i] as number][outputs[i | 1]].subscribe(listener);
cleanup !.push(subscription.unsubscribe, subscription);
}
}
@ -874,8 +884,8 @@ function createTNode(
*/
function setInputsForProperty(inputs: PropertyAliasValue, value: any): void {
for (let i = 0; i < inputs.length; i += 2) {
ngDevMode && assertDataInRange(inputs[i] as number);
data[inputs[i] as number][inputs[i | 1]] = value;
ngDevMode && assertDataInRange(inputs[i] as number, directives !);
directives ![inputs[i] as number][inputs[i | 1]] = value;
}
}
@ -894,9 +904,10 @@ function generatePropertyAliases(
if (size > 0) {
const start = tNodeFlags >> TNodeFlags.INDX_SHIFT;
const isInput = direction === BindingDirection.Input;
const defs = currentView.tView.directives !;
for (let i = start, ii = start + size; i < ii; i++) {
const directiveDef = tData ![i] as DirectiveDef<any>;
const directiveDef = defs[i] as DirectiveDef<any>;
const propertyAliasMap: {[publicName: string]: string} =
isInput ? directiveDef.inputs : directiveDef.outputs;
for (let publicName in propertyAliasMap) {
@ -1090,32 +1101,38 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
* NOTE: directives can be created in order other than the index order. They can also
* be retrieved before they are created in which case the value will be null.
*
* @param index Each directive in a `View` will have a unique index. Directives can
* be created or retrieved out of order.
* @param index Index to save the directive in the directives array
* @param elementIndex Index of the host element in the data array
* @param directive The directive instance.
* @param directiveDef DirectiveDef object which contains information about the template.
* @param localNames Names under which a query can retrieve the directive instance
* @param localRefs Names under which a query can retrieve the directive instance
*/
export function directiveCreate<T>(
index: number, directive: T, directiveDef: DirectiveDef<T>,
localNames?: (string | number)[] | null): T {
index: number, elementIndex: number, directive: T, directiveDef: DirectiveDef<T>,
localRefs?: string[] | null): T {
const instance = baseDirectiveCreate(index, directive, directiveDef);
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
const tNode: TNode|null = previousOrParentNode.tNode !;
if (firstTemplatePass && localNames) {
tNode.localNames = tNode.localNames ? tNode.localNames.concat(localNames) : localNames;
if (firstTemplatePass) {
// Init hooks are queued now so ngOnInit is called in host components before
// any projected components.
queueInitHooks(index, directiveDef.onInit, directiveDef.doCheck, currentView.tView);
if (directiveDef.hostBindings) queueHostBindingForCheck(index, elementIndex);
if (localRefs) {
const localNames = findMatchingLocalNames(directiveDef, localRefs, index);
tNode.localNames =
localNames && tNode.localNames ? tNode.localNames.concat(localNames) : localNames;
}
}
if (tNode && tNode.attrs) {
setInputsFromAttrs<T>(instance, directiveDef !.inputs, tNode);
setInputsFromAttrs<T>(index, instance, directiveDef.inputs, tNode);
}
// Init hooks are queued now so ngOnInit is called in host components before
// any projected components.
queueInitHooks(index, directiveDef.onInit, directiveDef.doCheck, currentView.tView);
return instance;
}
@ -1127,25 +1144,27 @@ export function directiveCreate<T>(
*/
export function baseDirectiveCreate<T>(
index: number, directive: T, directiveDef: DirectiveDef<T>): T {
let instance;
ngDevMode &&
assertNull(currentView.bindingStartIndex, 'directives should be created before any bindings');
ngDevMode && assertPreviousIsParent();
if (firstTemplatePass) {
const flags = previousOrParentNode.tNode !.flags;
previousOrParentNode.tNode !.flags =
(flags & TNodeFlags.SIZE_MASK) === 0 ? (index << TNodeFlags.INDX_SHIFT) | 1 : flags + 1;
}
ngDevMode && assertDataInRange(index - 1);
Object.defineProperty(
directive, NG_HOST_SYMBOL, {enumerable: false, value: previousOrParentNode});
data[index] = instance = directive;
if (directives == null) currentView.directives = directives = [];
if (index >= tData.length) {
tData[index] = directiveDef !;
ngDevMode && assertDataNext(index, directives);
directives[index] = directive;
if (firstTemplatePass) {
const defs = currentView.tView.directives || (currentView.tView.directives = []);
ngDevMode && assertDataNext(index, defs);
defs[index] = (directiveDef);
const flags = previousOrParentNode.tNode !.flags;
previousOrParentNode.tNode !.flags =
(flags & TNodeFlags.SIZE_MASK) === 0 ? (index << TNodeFlags.INDX_SHIFT) | 1 : flags + 1;
}
const diPublic = directiveDef !.diPublic;
@ -1158,19 +1177,19 @@ export function baseDirectiveCreate<T>(
(previousOrParentNode as LElementNode).native, directiveDef !.attributes as string[]);
}
return instance;
return directive;
}
/**
* Sets initial input properties on directive instances from attribute data
*
* @param directiveIndex Index of the directive in directives array
* @param instance Instance of the directive on which to set the initial inputs
* @param inputs The list of inputs from the directive def
* @param tNode The static data for this node
*/
function setInputsFromAttrs<T>(instance: T, inputs: {[key: string]: string}, tNode: TNode): void {
const directiveIndex = (previousOrParentNode.tNode !.flags & TNodeFlags.SIZE_MASK) - 1;
function setInputsFromAttrs<T>(
directiveIndex: number, instance: T, inputs: {[key: string]: string}, tNode: TNode): void {
let initialInputData = tNode.initialInputs as InitialInputData | undefined;
if (initialInputData === undefined || directiveIndex >= initialInputData.length) {
initialInputData = generateInitialInputs(directiveIndex, inputs, tNode);
@ -1266,7 +1285,7 @@ export function container(
// Containers are added to the current view tree instead of their embedded views
// because views can be removed and re-inserted.
addToViewTree(node.data);
hack_declareDirectives(index, index, directiveTypes, localRefs);
hack_declareDirectives(getNextDirectiveIndex(index), index, directiveTypes, localRefs);
isParent = false;
ngDevMode && assertNodeType(previousOrParentNode, LNodeType.Container);
@ -1279,6 +1298,12 @@ export function container(
}
}
/** Retrieves the next directive index to write */
function getNextDirectiveIndex(index: number): number {
return firstTemplatePass ? (directives ? directives.length : 0) :
(tData[index] as TNode).flags >> TNodeFlags.INDX_SHIFT;
}
/**
* Sets a container up to receive views.
*
@ -1461,10 +1486,10 @@ export function componentRefresh<T>(directiveIndex: number, elementIndex: number
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
if (viewAttached(hostView) && hostView.flags & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
ngDevMode && assertDataInRange(directiveIndex);
const template = (tData[directiveIndex] as ComponentDef<any>).template;
ngDevMode && assertDataInRange(directiveIndex, directives !);
const template = (currentView.tView.directives ![directiveIndex] as ComponentDef<any>).template;
detectChangesInternal(
hostView, element, template, getDirectiveInstance<T>(data[directiveIndex]));
hostView, element, template, getDirectiveInstance<T>(directives ![directiveIndex]));
}
}
@ -1770,7 +1795,7 @@ export function detectChanges<T>(component: T): void {
const hostNode = _getComponentHostLElementNode(component);
ngDevMode && assertNotNull(hostNode.data, 'Component host node should be attached to an LView');
const componentIndex = hostNode.tNode !.flags >> TNodeFlags.INDX_SHIFT;
const template = (hostNode.view.tView.data[componentIndex] as ComponentDef<T>).template;
const template = (hostNode.view.tView.directives ![componentIndex] as ComponentDef<T>).template;
detectChangesInternal(hostNode.data as LView, hostNode, template, component);
}
@ -2035,10 +2060,17 @@ export function store<T>(index: number, value: T): void {
/** Retrieves a value from the `data`. */
export function load<T>(index: number): T {
ngDevMode && assertDataInRange(index, data);
ngDevMode && assertDataInRange(index);
return data[index];
}
/** Retrieves a value from the `directives` array. */
export function loadDirective<T>(index: number): T {
ngDevMode && assertNotNull(directives, 'Directives array should be defined if reading a dir.');
ngDevMode && assertDataInRange(index, directives !);
return directives ![index];
}
/** Gets the current binding value and increments the binding index. */
export function consumeBinding(): any {
ngDevMode && assertDataInRange(bindingIndex);
@ -2087,7 +2119,7 @@ export function getTView(): TView {
}
export function getDirectiveInstance<T>(instanceOrArray: T | [T]): T {
// Directives with content queries store an array in data[directiveIndex]
// Directives with content queries store an array in directives[directiveIndex]
// with the instance as the first index
return Array.isArray(instanceOrArray) ? instanceOrArray[0] : instanceOrArray;
}
@ -2105,8 +2137,9 @@ function assertDataInRange(index: number, arr?: any[]) {
assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index');
}
function assertDataNext(index: number) {
assertEqual(data.length, index, 'index expected to be at the end of data');
function assertDataNext(index: number, arr?: any[]) {
if (arr == null) arr = data;
assertEqual(arr.length, index, 'index expected to be at the end of arr');
}
export function _getComponentHostLElementNode<T>(component: T): LElementNode {

View File

@ -7,12 +7,13 @@
*/
import {LContainer} from './container';
import {ComponentTemplate, DirectiveDef, PipeDef} from './definition';
import {ComponentDef, ComponentTemplate, DirectiveDef, PipeDef} from './definition';
import {LElementNode, LViewNode, TNode} from './node';
import {LQueries} from './query';
import {Renderer3} from './renderer';
/**
* `LView` 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
@ -131,7 +132,7 @@ export interface LView {
* This array stores all element/text/container nodes created inside this view
* and their bindings. Stored as an array rather than a linked list so we can
* look up nodes directly in the case of forward declaration or bindings
* (e.g. E(1))..
* (e.g. E(1)).
*
* All bindings for a given view are stored in the order in which they
* appear in the template, starting with `bindingStartIndex`.
@ -140,6 +141,14 @@ export interface LView {
*/
readonly data: any[];
/**
* An array of directive instances in the current view.
*
* These must be stored separately from LNodes because their presence is
* unknown at compile-time and thus space cannot be reserved in data[].
*/
directives: any[]|null;
/**
* The static data for this view. We need a reference to this so we can easily walk up the
* node tree in DI and get the TView.data array associated with a node (where the
@ -210,9 +219,17 @@ export interface LViewOrLContainer {
* Stored on the template function as ngPrivateData.
*/
export interface TView {
/** Static data equivalent of LView.data[]. Contains TNodes and directive defs. */
/** Static data equivalent of LView.data[]. Contains TNodes. */
data: TData;
/**
* Directive and component defs for this view
*
* Defs are stored at the same index in TView.directives[] as their instances
* are stored in LView.directives[]. This simplifies lookup in DI.
*/
directives: (ComponentDef<any>|DirectiveDef<any>)[]|null;
/** Whether or not this template has been processed. */
firstTemplatePass: boolean;
@ -278,8 +295,22 @@ export interface TView {
destroyHooks: HookData|null;
/**
* A list of element indices for child components that will need to be refreshed when the
* current view has finished its check.
* Array of pipe ngOnDestroy hooks that should be executed when this view is destroyed.
*
* Even indices: Index of pipe in data
* Odd indices: Hook function
*
* These must be stored separately from directive destroy hooks because their contexts
* are stored in data.
*/
pipeDestroyHooks: HookData|null;
/**
* A list of directive and element indices for child components that will need to be
* refreshed when the current view has finished its check.
*
* Even indices: Directive indices
* Odd indices: Element indices
*/
components: number[]|null;
@ -340,11 +371,11 @@ export const enum LifecycleStage {
* Static data that corresponds to the instance-specific data array on an LView.
*
* Each node's static data is stored in tData at the same index that it's stored
* in the data array. Each directive/pipe's definition is stored here at the same index
* as its directive/pipe instance in the data array. Any nodes that do not have static
* in the data array. Each pipe's definition is stored here at the same index
* as its pipe instance in the data array. Any nodes that do not have static
* data store a null value in tData to avoid a sparse array.
*/
export type TData = (TNode | DirectiveDef<any>| PipeDef<any>| null)[];
export type TData = (TNode | PipeDef<any>| null)[];
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.

View File

@ -361,6 +361,7 @@ export function getParentState(state: LViewOrLContainer, rootView: LView): LView
function cleanUpView(view: LView): void {
removeListeners(view);
executeOnDestroys(view);
executePipeOnDestroys(view);
}
/** Removes listeners and unsubscribes from output subscriptions */
@ -384,7 +385,15 @@ function executeOnDestroys(view: LView): void {
const tView = view.tView;
let destroyHooks: HookData|null;
if (tView != null && (destroyHooks = tView.destroyHooks) != null) {
callHooks(view.data, destroyHooks);
callHooks(view.directives !, destroyHooks);
}
}
/** Calls pipe destroy hooks for this view */
function executePipeOnDestroys(view: LView): void {
const pipeDestroyHooks = view.tView && view.tView.pipeDestroyHooks;
if (pipeDestroyHooks) {
callHooks(view.data !, pipeDestroyHooks);
}
}

View File

@ -25,8 +25,8 @@ export function pipe<T>(index: number, pipeDef: PipeDef<T>, firstInstance?: T):
const tView = getTView();
if (tView.firstTemplatePass) {
tView.data[index] = pipeDef;
if (pipeDef.onDestroy != null) {
(tView.destroyHooks || (tView.destroyHooks = [])).push(index, pipeDef.onDestroy);
if (pipeDef.onDestroy) {
(tView.pipeDestroyHooks || (tView.pipeDestroyHooks = [])).push(index, pipeDef.onDestroy);
}
}
const pipeInstance = pipeDef.pure && firstInstance ? firstInstance : pipeDef.n();

View File

@ -194,11 +194,11 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null {
* @returns Index of a found directive or null when none found.
*/
function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
const tData = node.view.tView.data;
const defs = node.view.tView.directives !;
const flags = node.tNode !.flags;
for (let i = flags >> TNodeFlags.INDX_SHIFT, ii = i + (flags & TNodeFlags.SIZE_MASK); i < ii;
i++) {
const def = tData[i] as DirectiveDef<any>;
const def = defs[i] as DirectiveDef<any>;
if (def.diPublic && def.type === type) {
return i;
}
@ -214,7 +214,7 @@ function readFromNodeInjector(
} else {
const matchingIdx = geIdxOfMatchingDirective(node, read as Type<any>);
if (matchingIdx !== null) {
return node.view.data[matchingIdx];
return node.view.directives ![matchingIdx];
}
}
return null;

View File

@ -207,7 +207,7 @@ describe('change detection', () => {
if (cm) {
elementStart(0, MyComponent);
elementEnd();
elementStart(2, 'button', ['id', 'parent']);
elementStart(1, 'button', ['id', 'parent']);
{ listener('click', () => ctx.noop()); }
elementEnd();
}

View File

@ -69,7 +69,7 @@ describe('components & directives', () => {
if (cm) {
$r3$.ɵE(0, ChildComponent, $e0_attrs$, $e0_dirs$);
$r3$.ɵe();
$r3$.ɵT(3, '!');
$r3$.ɵT(1, '!');
}
}
});
@ -92,7 +92,7 @@ describe('components & directives', () => {
type: HostBindingDir,
factory: function HostBindingDir_Factory() { return new HostBindingDir(); },
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵp(elIndex, 'id', $r3$.ɵb($r3$.ɵld<HostBindingDir>(dirIndex).dirId));
$r3$.ɵp(elIndex, 'id', $r3$.ɵb($r3$.ɵd<HostBindingDir>(dirIndex).dirId));
}
});
// /NORMATIVE
@ -161,7 +161,7 @@ describe('components & directives', () => {
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {
if (cm) {
$r3$.ɵE(0, 'button', $e0_attrs$, $e0_dirs$);
$r3$.ɵT(2, 'Click');
$r3$.ɵT(1, 'Click');
$r3$.ɵe();
}
}
@ -224,7 +224,7 @@ describe('components & directives', () => {
type: HostBindingDir,
factory: function HostBindingDir_Factory() { return new HostBindingDir(); },
hostBindings: function HostBindingDir_HostBindings(dirIndex: $number$, elIndex: $number$) {
$r3$.ɵa(elIndex, 'aria-label', $r3$.ɵb($r3$.ɵld<HostBindingDir>(dirIndex).label));
$r3$.ɵa(elIndex, 'aria-label', $r3$.ɵb($r3$.ɵd<HostBindingDir>(dirIndex).label));
}
});
// /NORMATIVE

View File

@ -84,7 +84,7 @@ describe('content projection', () => {
template: function(ctx: $MyApp$, cm: $boolean$) {
if (cm) {
$r3$.ɵE(0, SimpleComponent);
$r3$.ɵT(2, 'content');
$r3$.ɵT(1, 'content');
$r3$.ɵe();
}
}

View File

@ -70,11 +70,11 @@ describe('lifecycle hooks', () => {
if (cm) {
$r3$.ɵE(0, LifecycleComp);
$r3$.ɵe();
$r3$.ɵE(2, LifecycleComp);
$r3$.ɵE(1, LifecycleComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1));
$r3$.ɵp(2, 'name', $r3$.ɵb(ctx.name2));
$r3$.ɵp(1, 'name', $r3$.ɵb(ctx.name2));
}
});
// /NORMATIVE

View File

@ -102,9 +102,9 @@ describe('queries', () => {
hostBindings: function ContentQueryComponent_HostBindings(
dirIndex: $number$, elIndex: $number$) {
let $tmp$: any;
const $instance$ = $r3$.ɵld<any[]>(dirIndex)[0];
$r3$.ɵqR($tmp$ = $r3$.ɵld<any[]>(dirIndex)[1]) && ($instance$.someDir = $tmp$.first);
$r3$.ɵqR($tmp$ = $r3$.ɵld<any[]>(dirIndex)[2]) && ($instance$.someDirList = $tmp$);
const $instance$ = $r3$.ɵd<any[]>(dirIndex)[0];
$r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[1]) && ($instance$.someDir = $tmp$.first);
$r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[2]) && ($instance$.someDirList = $tmp$);
},
template: function ContentQueryComponent_Template(
ctx: $ContentQueryComponent$, cm: $boolean$) {
@ -139,8 +139,8 @@ describe('queries', () => {
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {
if (cm) {
$r3$.ɵE(0, ContentQueryComponent);
contentQueryComp = $r3$.ɵld<any[]>(1)[0];
$r3$.ɵE(2, 'div', $e2_attrs$, $e2_dirs$);
contentQueryComp = $r3$.ɵd<any[]>(0)[0];
$r3$.ɵE(1, 'div', $e2_attrs$, $e2_dirs$);
$r3$.ɵe();
$r3$.ɵe();
}

View File

@ -7,7 +7,7 @@
*/
import {detectChanges} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, projection, projectionDef, text} from '../../src/render3/instructions';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions';
import {createComponent, renderComponent, toHtml} from './render_util';
@ -32,7 +32,7 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Child);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
});
@ -50,7 +50,7 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Child);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
});
@ -71,7 +71,7 @@ describe('content projection', () => {
if (cm) {
projectionDef(0);
elementStart(1, GrandChild);
{ projection(3, 0); }
{ projection(2, 0); }
elementEnd();
}
});
@ -79,10 +79,10 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'b');
text(3, 'Hello');
elementStart(1, 'b');
text(2, 'Hello');
elementEnd();
text(4, 'World!');
text(3, 'World!');
}
elementEnd();
}
@ -119,7 +119,7 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, ProjectedComp);
elementStart(1, ProjectedComp);
elementEnd();
}
elementEnd();
@ -143,13 +143,13 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
text(2, '(');
container(3);
text(4, ')');
text(1, '(');
container(2);
text(3, ')');
}
elementEnd();
}
containerRefreshStart(3);
containerRefreshStart(2);
{
if (ctx.value) {
if (embeddedViewStart(0)) {
@ -180,10 +180,10 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) {
if (cm) {
elementStart(0, Child);
{ container(2); }
{ container(1); }
elementEnd();
}
containerRefreshStart(2);
containerRefreshStart(1);
{
if (ctx.value) {
if (embeddedViewStart(0)) {
@ -219,13 +219,13 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
text(2, '(');
container(3);
text(4, ')');
text(1, '(');
container(2);
text(3, ')');
}
elementEnd();
}
containerRefreshStart(3);
containerRefreshStart(2);
{
if (ctx.value) {
if (embeddedViewStart(0)) {
@ -291,8 +291,8 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
childCmptInstance = load(1);
text(2, 'content');
childCmptInstance = loadDirective(0);
text(1, 'content');
}
elementEnd();
}
@ -342,8 +342,8 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
childCmptInstance = load(1);
text(2, 'content');
childCmptInstance = loadDirective(0);
text(1, 'content');
}
elementEnd();
}
@ -395,8 +395,8 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
childCmptInstance = load(1);
text(2, 'content');
childCmptInstance = loadDirective(0);
text(1, 'content');
}
elementEnd();
}
@ -432,7 +432,7 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Child);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
});
@ -486,8 +486,8 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
childCmptInstance = load(1);
text(2, 'content');
childCmptInstance = loadDirective(0);
text(1, 'content');
}
elementEnd();
}
@ -531,11 +531,11 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span', ['title', 'toFirst']);
{ text(3, '1'); }
elementStart(1, 'span', ['title', 'toFirst']);
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span', ['title', 'toSecond']);
{ text(5, '2'); }
elementStart(3, 'span', ['title', 'toSecond']);
{ text(4, '2'); }
elementEnd();
}
elementEnd();
@ -577,11 +577,11 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span', ['class', 'toFirst']);
{ text(3, '1'); }
elementStart(1, 'span', ['class', 'toFirst']);
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span', ['class', 'toSecond']);
{ text(5, '2'); }
elementStart(3, 'span', ['class', 'toSecond']);
{ text(4, '2'); }
elementEnd();
}
elementEnd();
@ -623,11 +623,11 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span', ['class', 'other toFirst']);
{ text(3, '1'); }
elementStart(1, 'span', ['class', 'other toFirst']);
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span', ['class', 'toSecond noise']);
{ text(5, '2'); }
elementStart(3, 'span', ['class', 'toSecond noise']);
{ text(4, '2'); }
elementEnd();
}
elementEnd();
@ -669,11 +669,11 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span', ['class', 'toFirst']);
{ text(3, '1'); }
elementStart(1, 'span', ['class', 'toFirst']);
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span', ['class', 'toSecond']);
{ text(5, '2'); }
elementStart(3, 'span', ['class', 'toSecond']);
{ text(4, '2'); }
elementEnd();
}
elementEnd();
@ -713,13 +713,13 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span', ['class', 'toFirst']);
{ text(3, '1'); }
elementStart(1, 'span', ['class', 'toFirst']);
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span');
{ text(5, 'remaining'); }
elementStart(3, 'span');
{ text(4, 'remaining'); }
elementEnd();
text(6, 'more remaining');
text(5, 'more remaining');
}
elementEnd();
}
@ -759,13 +759,13 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span');
{ text(3, '1'); }
elementStart(1, 'span');
{ text(2, '1'); }
elementEnd();
elementStart(4, 'span', ['class', 'toSecond']);
{ text(5, '2'); }
elementStart(3, 'span', ['class', 'toSecond']);
{ text(4, '2'); }
elementEnd();
text(6, 'remaining');
text(5, 'remaining');
}
elementEnd();
}
@ -809,9 +809,9 @@ describe('content projection', () => {
projectionDef(0);
elementStart(1, GrandChild);
{
projection(3, 0);
elementStart(4, 'span');
{ text(5, 'in child template'); }
projection(2, 0);
elementStart(3, 'span');
{ text(4, 'in child template'); }
elementEnd();
}
elementEnd();
@ -829,8 +829,8 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'span');
{ text(3, 'parent content'); }
elementStart(1, 'span');
{ text(2, 'parent content'); }
elementEnd();
}
elementEnd();
@ -873,10 +873,10 @@ describe('content projection', () => {
projectionDef(0);
elementStart(1, Card);
{
elementStart(3, 'h1', ['card-title', '']);
{ text(4, 'Title'); }
elementStart(2, 'h1', ['card-title', '']);
{ text(3, 'Title'); }
elementEnd();
projection(5, 0, 0, ['card-content', '']);
projection(4, 0, 0, ['card-content', '']);
}
elementEnd();
}
@ -890,7 +890,7 @@ describe('content projection', () => {
const App = createComponent('app', function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, CardWithTitle);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
});
@ -932,10 +932,10 @@ describe('content projection', () => {
projectionDef(0);
elementStart(1, Card);
{
elementStart(3, 'h1', ['ngProjectAs', '[card-title]']);
{ text(4, 'Title'); }
elementStart(2, 'h1', ['ngProjectAs', '[card-title]']);
{ text(3, 'Title'); }
elementEnd();
projection(5, 0, 0, ['ngProjectAs', '[card-content]']);
projection(4, 0, 0, ['ngProjectAs', '[card-content]']);
}
elementEnd();
}
@ -949,7 +949,7 @@ describe('content projection', () => {
const App = createComponent('app', function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, CardWithTitle);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
});
@ -982,11 +982,11 @@ describe('content projection', () => {
if (cm) {
elementStart(0, Child);
{
elementStart(2, 'div', ['ngProjectAs', 'span']);
{ text(3, 'should not project'); }
elementStart(1, 'div', ['ngProjectAs', 'span']);
{ text(2, 'should not project'); }
elementEnd();
elementStart(4, 'div');
{ text(5, 'should project'); }
elementStart(3, 'div');
{ text(4, 'should project'); }
elementEnd();
}
elementEnd();
@ -1021,10 +1021,10 @@ describe('content projection', () => {
const Parent = createComponent('parent', function(ctx: {value: any}, cm: boolean) {
if (cm) {
elementStart(0, Child);
{ container(2, undefined, undefined, 'div'); }
{ container(1, undefined, undefined, 'div'); }
elementEnd();
}
containerRefreshStart(2);
containerRefreshStart(1);
{
if (true) {
if (embeddedViewStart(0)) {

View File

@ -11,7 +11,7 @@ import {ChangeDetectorRef, ElementRef, TemplateRef, ViewContainerRef} from '@ang
import {defineComponent} from '../../src/render3/definition';
import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {LInjector} from '../../src/render3/interfaces/injector';
import {LNodeType} from '../../src/render3/interfaces/node';
import {LViewFlags} from '../../src/render3/interfaces/view';
@ -30,10 +30,11 @@ describe('di', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', null, [Directive]);
{ text(2); }
{ text(1); }
elementEnd();
}
textBinding(2, bind(load<Directive>(1).value));
// TODO: remove loadDirective when removing directive references
textBinding(1, bind(loadDirective<Directive>(0).value));
}
expect(renderToHtml(Template, {})).toEqual('<div>Created</div>');
@ -67,13 +68,14 @@ describe('di', () => {
if (cm) {
elementStart(0, 'div', null, [DirectiveA]);
{
elementStart(2, 'span', null, [DirectiveB, DirectiveC]);
{ text(5); }
elementStart(1, 'span', null, [DirectiveB, DirectiveC]);
{ text(2); }
elementEnd();
}
elementEnd();
}
textBinding(5, bind(load<DirectiveC>(4).value));
// TODO: remove loadDirective when removing directive references
textBinding(2, bind(loadDirective<DirectiveC>(2).value));
}
expect(renderToHtml(Template, {})).toEqual('<div><span>AB</span></div>');
@ -108,12 +110,14 @@ describe('di', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', null, [Directive, DirectiveSameInstance]);
{ text(3); }
{ text(1); }
elementEnd();
}
// TODO: remove loadDirective when removing directive references
textBinding(
3, interpolation2(
'', load<Directive>(1).value, '-', load<DirectiveSameInstance>(2).value, ''));
1, interpolation2(
'', loadDirective<Directive>(0).value, '-',
loadDirective<DirectiveSameInstance>(1).value, ''));
}
expect(renderToHtml(Template, {})).toEqual('<div>ElementRef-true</div>');
@ -149,11 +153,13 @@ describe('di', () => {
function Template(ctx: any, cm: any) {
if (cm) {
container(0, [Directive, DirectiveSameInstance], function() {});
text(3);
text(1);
}
// TODO: remove loadDirective when removing directive references
textBinding(
3, interpolation2(
'', load<Directive>(1).value, '-', load<DirectiveSameInstance>(2).value, ''));
1, interpolation2(
'', loadDirective<Directive>(0).value, '-',
loadDirective<DirectiveSameInstance>(1).value, ''));
}
expect(renderToHtml(Template, {})).toEqual('TemplateRef-true');
@ -189,12 +195,14 @@ describe('di', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', null, [Directive, DirectiveSameInstance]);
{ text(3); }
{ text(1); }
elementEnd();
}
// TODO: remove loadDirective when removing directive references
textBinding(
3, interpolation2(
'', load<Directive>(1).value, '-', load<DirectiveSameInstance>(2).value, ''));
1, interpolation2(
'', loadDirective<Directive>(0).value, '-',
loadDirective<DirectiveSameInstance>(1).value, ''));
}
expect(renderToHtml(Template, {})).toEqual('<div>ViewContainerRef-true</div>');
@ -255,9 +263,10 @@ describe('di', () => {
if (cm) {
elementStart(0, MyComp, $e0_attrs$, [Directive, DirectiveSameInstance]);
elementEnd();
text(4);
text(1);
}
textBinding(4, bind(load<Directive>(2).value));
// TODO: remove loadDirective when removing directive references
textBinding(1, bind(loadDirective<Directive>(1).value));
}
});
}
@ -284,10 +293,11 @@ describe('di', () => {
template: function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
{ text(3); }
{ text(1); }
elementEnd();
}
textBinding(3, bind(load<Directive>(1).value));
// TODO: remove loadDirective when removing directive references
textBinding(1, bind(loadDirective<Directive>(0).value));
}
});
}
@ -318,13 +328,14 @@ describe('di', () => {
if (cm) {
elementStart(0, MyComp);
{
elementStart(2, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
elementStart(1, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
elementEnd();
}
elementEnd();
text(5);
text(2);
}
textBinding(5, bind(load<Directive>(3).value));
// TODO: remove loadDirective when removing directive references
textBinding(2, bind(loadDirective<Directive>(1).value));
}
});
}
@ -363,10 +374,11 @@ describe('di', () => {
if (ctx.showing) {
if (embeddedViewStart(0)) {
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
{ text(3); }
{ text(1); }
elementEnd();
}
textBinding(3, bind(load<Directive>(1).value));
// TODO: remove loadDirective when removing directive references
textBinding(1, bind(loadDirective<Directive>(0).value));
}
embeddedViewEnd();
}
@ -424,10 +436,11 @@ describe('di', () => {
function C1(ctx1: any, cm1: boolean) {
if (cm1) {
elementStart(0, 'div', $e0_attrs$, [Directive, DirectiveSameInstance]);
{ text(3); }
{ text(1); }
elementEnd();
}
textBinding(3, bind(load<Directive>(1).value));
// TODO: remove loadDirective when removing directive references
textBinding(1, bind(loadDirective<Directive>(0).value));
}
}
});
@ -591,19 +604,21 @@ describe('di', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', null, [ParentDirective]);
{ container(2); }
{ container(1); }
elementEnd();
}
containerRefreshStart(2);
containerRefreshStart(1);
{
if (embeddedViewStart(0)) {
elementStart(0, 'span', null, [ChildDirective, Child2Directive]);
{ text(3); }
{ text(1); }
elementEnd();
}
// TODO: remove loadDirective when removing directive references
textBinding(
3, interpolation2(
'', load<ChildDirective>(1).value, '-', load<Child2Directive>(2).value, ''));
1, interpolation2(
'', loadDirective<ChildDirective>(0).value, '-',
loadDirective<Child2Directive>(1).value, ''));
embeddedViewEnd();
}
containerRefreshEnd();

View File

@ -7,7 +7,7 @@
*/
import {defineDirective} from '../../src/render3/index';
import {bind, elementEnd, elementProperty, elementStart, load} from '../../src/render3/instructions';
import {bind, elementEnd, elementProperty, elementStart, loadDirective} from '../../src/render3/instructions';
import {renderToHtml} from './render_util';
@ -24,7 +24,8 @@ describe('directive', () => {
type: Directive,
factory: () => directiveInstance = new Directive,
hostBindings: (directiveIndex: number, elementIndex: number) => {
elementProperty(elementIndex, 'className', bind(load<Directive>(directiveIndex).klass));
elementProperty(
elementIndex, 'className', bind(loadDirective<Directive>(directiveIndex).klass));
}
});
}

View File

@ -7,7 +7,7 @@
*/
import {defineComponent, defineDirective} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {renderToHtml} from './render_util';
@ -35,9 +35,10 @@ describe('exports', () => {
if (cm) {
elementStart(0, MyComponent, null, null, ['myComp', '']);
elementEnd();
text(2);
text(1);
}
textBinding(2, load<MyComponent>(1).name);
// TODO: replace loadDirective when removing directive refs
textBinding(1, loadDirective<MyComponent>(0).name);
}
class MyComponent {
@ -80,10 +81,11 @@ describe('exports', () => {
if (cm) {
elementStart(0, MyComponent, null, null, ['myComp', '']);
elementEnd();
elementStart(2, 'div', null, [MyDir]);
elementStart(1, 'div', null, [MyDir]);
elementEnd();
}
elementProperty(2, 'myDir', bind(load<MyComponent>(1)));
// TODO: replace loadDirective when removing directive refs
elementProperty(1, 'myDir', bind(loadDirective<MyComponent>(0)));
}
renderToHtml(Template, {});
@ -97,14 +99,16 @@ describe('exports', () => {
if (cm) {
elementStart(0, 'div', null, [SomeDir], ['myDir', 'someDir']);
elementEnd();
text(2);
text(1);
}
textBinding(2, load<SomeDir>(1).name);
// TODO: replace loadDirective when removing directive refs
textBinding(1, loadDirective<SomeDir>(0).name);
}
class SomeDir {
name = 'Drew';
static ngDirectiveDef = defineDirective({type: SomeDir, factory: () => new SomeDir});
static ngDirectiveDef =
defineDirective({type: SomeDir, factory: () => new SomeDir, exportAs: 'someDir'});
}
expect(renderToHtml(Template, {})).toEqual('<div></div>Drew');
@ -206,10 +210,11 @@ describe('exports', () => {
if (cm) {
elementStart(0, 'div', null, [MyDir]);
elementEnd();
elementStart(2, MyComponent, null, null, ['myComp', '']);
elementStart(1, MyComponent, null, null, ['myComp', '']);
elementEnd();
}
elementProperty(0, 'myDir', bind(load<MyComponent>(3)));
// TODO: replace loadDirective when removing directive refs
elementProperty(0, 'myDir', bind(loadDirective<MyComponent>(1)));
}
renderToHtml(Template, {});
@ -225,11 +230,12 @@ describe('exports', () => {
text(1);
elementStart(2, MyComponent, null, null, ['myComp', '']);
elementEnd();
elementStart(4, 'input', ['value', 'one'], null, ['myInput', '']);
elementStart(3, 'input', ['value', 'one'], null, ['myInput', '']);
elementEnd();
}
let myInput = elementStart(4);
let myComp = load<MyComponent>(3);
let myInput = elementStart(3);
// TODO: replace loadDirective when removing directive refs
let myComp = loadDirective<MyComponent>(0);
textBinding(0, bind(myInput && (myInput as any).value));
textBinding(1, bind(myComp && myComp.name));
}

View File

@ -7,7 +7,7 @@
*/
import {defineComponent, defineDirective} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleNamed, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleNamed, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {ComponentFixture, containerEl, renderToHtml} from './render_util';
@ -210,7 +210,7 @@ describe('render3 integration test', () => {
if (cm) {
elementStart(0, TodoComponent);
elementEnd();
text(2, 'two');
text(1, 'two');
}
}
expect(renderToHtml(Template, null)).toEqual('<todo><p>Todo one</p></todo>two');
@ -225,7 +225,7 @@ describe('render3 integration test', () => {
if (cm) {
elementStart(0, TodoComponent);
elementEnd();
elementStart(2, TodoComponent);
elementStart(1, TodoComponent);
elementEnd();
}
}
@ -252,7 +252,8 @@ describe('render3 integration test', () => {
hostBindings: function(directiveIndex: number, elementIndex: number): void {
// host bindings
elementProperty(
elementIndex, 'title', bind(load<TodoComponentHostBinding>(directiveIndex).title));
elementIndex, 'title',
bind(loadDirective<TodoComponentHostBinding>(directiveIndex).title));
}
});
}
@ -460,12 +461,12 @@ describe('render3 integration test', () => {
function parentTemplate(ctx: ParentCtx, cm: boolean) {
if (cm) {
elementStart(0, ChildComponent);
{ container(2); }
{ container(1); }
elementEnd();
}
elementProperty(0, 'beforeTree', bind(ctx.beforeTree));
elementProperty(0, 'afterTree', bind(ctx.afterTree));
containerRefreshStart(2);
containerRefreshStart(1);
{
const cm0 = embeddedViewStart(0);
{ showTree({tree: ctx.projectedTree}, cm0); }
@ -636,7 +637,8 @@ describe('render3 integration test', () => {
return hostBindingDir = new HostBindingDir();
},
hostBindings: function HostBindingDir_HostBindings(dirIndex: number, elIndex: number) {
elementAttribute(elIndex, 'aria-label', bind(load<HostBindingDir>(dirIndex).label));
elementAttribute(
elIndex, 'aria-label', bind(loadDirective<HostBindingDir>(dirIndex).label));
}
});
}

View File

@ -120,11 +120,11 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
elementStart(2, Parent);
elementStart(1, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(1, 'val', 2);
}
renderToHtml(Template, {});
@ -175,7 +175,7 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ elementStart(2, ProjectedComp); }
{ elementStart(1, ProjectedComp); }
elementEnd();
}
}
@ -196,16 +196,16 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ elementStart(2, ProjectedComp); }
{ elementStart(1, ProjectedComp); }
elementEnd();
elementStart(4, Comp);
{ elementStart(6, ProjectedComp); }
elementStart(2, Comp);
{ elementStart(3, ProjectedComp); }
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 1);
elementProperty(4, 'val', 2);
elementProperty(6, 'val', 2);
elementProperty(1, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(3, 'val', 2);
}
renderToHtml(Template, {});
@ -258,13 +258,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
elementEnd();
container(2);
elementStart(3, Comp);
container(1);
elementStart(2, Comp);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 5);
containerRefreshStart(2);
elementProperty(2, 'val', 5);
containerRefreshStart(1);
{
for (let j = 2; j < 5; j++) {
if (embeddedViewStart(0)) {
@ -298,13 +298,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
container(2);
elementStart(3, Parent);
container(1);
elementStart(2, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 5);
containerRefreshStart(2);
elementProperty(2, 'val', 5);
containerRefreshStart(1);
{
for (let j = 2; j < 5; j++) {
if (embeddedViewStart(0)) {
@ -475,7 +475,7 @@ describe('lifecycles', () => {
if (cm) {
projectionDef(0);
elementStart(1, Comp);
{ projection(3, 0); }
{ projection(2, 0); }
elementEnd();
}
elementProperty(1, 'val', bind(ctx.val));
@ -512,7 +512,7 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
}
@ -548,7 +548,7 @@ describe('lifecycles', () => {
if (ctx.condition) {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
embeddedViewEnd();
@ -576,7 +576,7 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Parent);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
}
@ -595,14 +595,14 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Parent);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
elementStart(3, Parent);
{ text(5, 'content'); }
elementStart(2, Parent);
{ text(3, 'content'); }
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 2);
elementProperty(2, 'val', 2);
}
renderToHtml(Template, {});
@ -624,8 +624,8 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
{
elementStart(2, ProjectedComp);
{ text(4, 'content'); }
elementStart(1, ProjectedComp);
{ text(2, 'content'); }
elementEnd();
}
elementEnd();
@ -654,23 +654,23 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
{
elementStart(2, ProjectedComp);
{ text(4, 'content'); }
elementStart(1, ProjectedComp);
{ text(2, 'content'); }
elementEnd();
}
elementEnd();
elementStart(5, Parent);
elementStart(3, Parent);
{
elementStart(7, ProjectedComp);
{ text(9, 'content'); }
elementStart(4, ProjectedComp);
{ text(5, 'content'); }
elementEnd();
}
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 1);
elementProperty(5, 'val', 2);
elementProperty(7, 'val', 2);
elementProperty(1, 'val', 1);
elementProperty(3, 'val', 2);
elementProperty(4, 'val', 2);
}
renderToHtml(Template, {});
@ -688,21 +688,21 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
container(3);
elementStart(4, Comp);
{ text(6, 'content'); }
container(2);
elementStart(3, Comp);
{ text(4, 'content'); }
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(4, 'val', 4);
containerRefreshStart(3);
elementProperty(3, 'val', 4);
containerRefreshStart(2);
{
for (let i = 2; i < 4; i++) {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
elementProperty(0, 'val', i);
@ -719,21 +719,21 @@ describe('lifecycles', () => {
function ForLoopWithChildrenTemplate(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Parent);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
container(3);
elementStart(4, Parent);
{ text(6, 'content'); }
container(2);
elementStart(3, Parent);
{ text(4, 'content'); }
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(4, 'val', 4);
containerRefreshStart(3);
elementProperty(3, 'val', 4);
containerRefreshStart(2);
{
for (let i = 2; i < 4; i++) {
if (embeddedViewStart(0)) {
elementStart(0, Parent);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
elementProperty(0, 'val', i);
@ -764,7 +764,7 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ text(2, 'content'); }
{ text(1, 'content'); }
elementEnd();
}
}
@ -956,11 +956,11 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
elementStart(2, Parent);
elementStart(1, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(1, 'val', 2);
}
renderToHtml(Template, {});
expect(events).toEqual(['comp1', 'comp2', 'parent1', 'parent2']);
@ -977,7 +977,7 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
{
elementStart(2, ProjectedComp);
elementStart(1, ProjectedComp);
elementEnd();
}
elementEnd();
@ -1001,21 +1001,21 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
{
elementStart(2, ProjectedComp);
elementStart(1, ProjectedComp);
elementEnd();
}
elementEnd();
elementStart(4, Comp);
elementStart(2, Comp);
{
elementStart(6, ProjectedComp);
elementStart(3, ProjectedComp);
elementEnd();
}
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 1);
elementProperty(4, 'val', 2);
elementProperty(6, 'val', 2);
elementProperty(1, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(3, 'val', 2);
}
renderToHtml(Template, {});
@ -1032,13 +1032,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
{
elementStart(2, ProjectedComp);
elementStart(1, ProjectedComp);
elementEnd();
}
elementEnd();
}
elementProperty(0, 'val', bind(ctx.val));
elementProperty(2, 'val', bind(ctx.val));
elementProperty(1, 'val', bind(ctx.val));
});
/**
@ -1049,11 +1049,11 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, ParentComp);
elementEnd();
elementStart(2, ParentComp);
elementStart(1, ParentComp);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(1, 'val', 2);
}
renderToHtml(Template, {});
@ -1072,13 +1072,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
elementEnd();
container(2);
elementStart(3, Comp);
container(1);
elementStart(2, Comp);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 4);
containerRefreshStart(2);
elementProperty(2, 'val', 4);
containerRefreshStart(1);
{
for (let i = 2; i < 4; i++) {
if (embeddedViewStart(0)) {
@ -1109,13 +1109,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
container(2);
elementStart(3, Parent);
container(1);
elementStart(2, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 4);
containerRefreshStart(2);
elementProperty(2, 'val', 4);
containerRefreshStart(1);
{
for (let i = 2; i < 4; i++) {
if (embeddedViewStart(0)) {
@ -1191,13 +1191,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
container(2);
elementStart(3, Parent);
container(1);
elementStart(2, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(3, 'val', 4);
containerRefreshStart(2);
elementProperty(2, 'val', 4);
containerRefreshStart(1);
{
for (let i = 2; i < 4; i++) {
if (embeddedViewStart(0)) {
@ -1339,11 +1339,11 @@ describe('lifecycles', () => {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
elementEnd();
elementStart(2, Comp);
elementStart(1, Comp);
elementEnd();
}
elementProperty(0, 'val', bind('1'));
elementProperty(2, 'val', bind('2'));
elementProperty(1, 'val', bind('2'));
embeddedViewEnd();
}
}
@ -1448,21 +1448,21 @@ describe('lifecycles', () => {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
{
elementStart(2, ProjectedComp);
elementStart(1, ProjectedComp);
elementEnd();
}
elementEnd();
elementStart(4, Comp);
elementStart(2, Comp);
{
elementStart(6, ProjectedComp);
elementStart(3, ProjectedComp);
elementEnd();
}
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 1);
elementProperty(4, 'val', 2);
elementProperty(6, 'val', 2);
elementProperty(1, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(3, 'val', 2);
embeddedViewEnd();
}
}
@ -1497,13 +1497,13 @@ describe('lifecycles', () => {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
elementEnd();
container(2);
elementStart(3, Comp);
container(1);
elementStart(2, Comp);
elementEnd();
}
elementProperty(0, 'val', bind('1'));
elementProperty(3, 'val', bind('3'));
containerRefreshStart(2);
elementProperty(2, 'val', bind('3'));
containerRefreshStart(1);
{
if (ctx.condition2) {
if (embeddedViewStart(0)) {
@ -1567,13 +1567,13 @@ describe('lifecycles', () => {
if (embeddedViewStart(0)) {
elementStart(0, Comp);
elementEnd();
container(2);
elementStart(3, Comp);
container(1);
elementStart(2, Comp);
elementEnd();
}
elementProperty(0, 'val', bind('1'));
elementProperty(3, 'val', bind('5'));
containerRefreshStart(2);
elementProperty(2, 'val', bind('5'));
containerRefreshStart(1);
{
for (let j = 2; j < ctx.len; j++) {
if (embeddedViewStart(0)) {
@ -1645,10 +1645,10 @@ describe('lifecycles', () => {
elementEnd();
elementStart(2, Comp);
elementEnd();
elementStart(4, 'button');
elementStart(3, 'button');
{
listener('click', ctx.onClick.bind(ctx));
text(5, 'Click me');
text(4, 'Click me');
}
elementEnd();
}
@ -1868,13 +1868,13 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
elementStart(2, Parent);
elementStart(1, Parent);
elementEnd();
}
elementProperty(0, 'val1', bind(1));
elementProperty(0, 'publicName', bind(1));
elementProperty(2, 'val1', bind(2));
elementProperty(2, 'publicName', bind(2));
elementProperty(1, 'val1', bind(2));
elementProperty(1, 'publicName', bind(2));
}
renderToHtml(Template, {});
@ -1935,13 +1935,13 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ elementStart(2, ProjectedComp); }
{ elementStart(1, ProjectedComp); }
elementEnd();
}
elementProperty(0, 'val1', bind(1));
elementProperty(0, 'publicName', bind(1));
elementProperty(2, 'val1', bind(2));
elementProperty(2, 'publicName', bind(2));
elementProperty(1, 'val1', bind(2));
elementProperty(1, 'publicName', bind(2));
}
renderToHtml(Template, {});
@ -1963,20 +1963,20 @@ describe('lifecycles', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, Comp);
{ elementStart(2, ProjectedComp); }
{ elementStart(1, ProjectedComp); }
elementEnd();
elementStart(4, Comp);
{ elementStart(6, ProjectedComp); }
elementStart(2, Comp);
{ elementStart(3, ProjectedComp); }
elementEnd();
}
elementProperty(0, 'val1', bind(1));
elementProperty(0, 'publicName', bind(1));
elementProperty(2, 'val1', bind(2));
elementProperty(2, 'publicName', bind(2));
elementProperty(4, 'val1', bind(3));
elementProperty(4, 'publicName', bind(3));
elementProperty(6, 'val1', bind(4));
elementProperty(6, 'publicName', bind(4));
elementProperty(1, 'val1', bind(2));
elementProperty(1, 'publicName', bind(2));
elementProperty(2, 'val1', bind(3));
elementProperty(2, 'publicName', bind(3));
elementProperty(3, 'val1', bind(4));
elementProperty(3, 'publicName', bind(4));
}
renderToHtml(Template, {});
@ -2042,15 +2042,15 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
elementEnd();
container(2);
elementStart(3, Comp);
container(1);
elementStart(2, Comp);
elementEnd();
}
elementProperty(0, 'val1', bind(1));
elementProperty(0, 'publicName', bind(1));
elementProperty(3, 'val1', bind(5));
elementProperty(3, 'publicName', bind(5));
containerRefreshStart(2);
elementProperty(2, 'val1', bind(5));
elementProperty(2, 'publicName', bind(5));
containerRefreshStart(1);
{
for (let j = 2; j < 5; j++) {
if (embeddedViewStart(0)) {
@ -2091,15 +2091,15 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
container(2);
elementStart(3, Parent);
container(1);
elementStart(2, Parent);
elementEnd();
}
elementProperty(0, 'val1', bind(1));
elementProperty(0, 'publicName', bind(1));
elementProperty(3, 'val1', bind(5));
elementProperty(3, 'publicName', bind(5));
containerRefreshStart(2);
elementProperty(2, 'val1', bind(5));
elementProperty(2, 'publicName', bind(5));
containerRefreshStart(1);
{
for (let j = 2; j < 5; j++) {
if (embeddedViewStart(0)) {
@ -2176,11 +2176,11 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Comp);
elementEnd();
elementStart(2, Comp);
elementStart(1, Comp);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(1, 'val', 2);
}
renderToHtml(Template, {});
@ -2218,11 +2218,11 @@ describe('lifecycles', () => {
if (cm) {
elementStart(0, Parent);
elementEnd();
elementStart(2, Parent);
elementStart(1, Parent);
elementEnd();
}
elementProperty(0, 'val', 1);
elementProperty(2, 'val', 2);
elementProperty(1, 'val', 2);
}
renderToHtml(Template, {});

View File

@ -246,7 +246,7 @@ describe('event listeners', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'button', ['hostListenerDir', ''], [HostListenerDir]);
text(2, 'Click');
text(1, 'Click');
elementEnd();
}
}
@ -339,7 +339,7 @@ describe('event listeners', () => {
text(0, 'Hello');
elementStart(1, MyComp);
elementEnd();
elementStart(3, MyComp);
elementStart(2, MyComp);
elementEnd();
}
embeddedViewEnd();

View File

@ -248,7 +248,7 @@ describe('outputs', () => {
listener('change', function() { return ctx.onChange(); });
}
elementEnd();
elementStart(4, DestroyComp);
elementStart(3, DestroyComp);
elementEnd();
}
embeddedViewEnd();

View File

@ -10,7 +10,7 @@ import {Directive, OnChanges, OnDestroy, Pipe, PipeTransform, SimpleChange, Simp
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {NgOnChangesFeature, defineComponent, defineDirective, definePipe} from '../../src/render3/definition';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe';
import {RenderLog, getRendererFactory2, patchLoggingRenderer2} from './imported_renderer2';
@ -68,11 +68,11 @@ describe('pipe', () => {
function Template(ctx: string, cm: boolean) {
if (cm) {
elementStart(0, 'div', null, [MyDir]);
pipe(2, DoublePipe.ngPipeDef);
pipe(1, DoublePipe.ngPipeDef);
elementEnd();
}
elementProperty(0, 'elprop', bind(pipeBind1(2, ctx)));
directive = load(1);
elementProperty(0, 'elprop', bind(pipeBind1(1, ctx)));
directive = loadDirective(0);
}
renderToHtml(Template, 'a');
expect(directive !.dirProp).toEqual('aa');

View File

@ -9,7 +9,7 @@
import {EventEmitter} from '@angular/core';
import {defineComponent, defineDirective, tick} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, load, text, textBinding} from '../../src/render3/instructions';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, listener, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {ComponentFixture, renderToHtml} from './render_util';
@ -71,7 +71,7 @@ describe('elementProperty', () => {
tag: 'host-binding-comp',
factory: () => new HostBindingComp(),
hostBindings: (dirIndex: number, elIndex: number) => {
const instance = load(dirIndex) as HostBindingComp;
const instance = loadDirective(dirIndex) as HostBindingComp;
elementProperty(elIndex, 'id', bind(instance.id));
},
template: (ctx: HostBindingComp, cm: boolean) => {}
@ -115,7 +115,7 @@ describe('elementProperty', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'button', null, [MyButton, OtherDir]);
{ text(3, 'Click me'); }
{ text(1, 'Click me'); }
elementEnd();
}
@ -141,7 +141,7 @@ describe('elementProperty', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'button', null, [MyButton]);
{ text(2, 'Click me'); }
{ text(1, 'Click me'); }
elementEnd();
}
@ -206,7 +206,7 @@ describe('elementProperty', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'button', null, [MyButton, OtherDisabledDir]);
{ text(3, 'Click me'); }
{ text(1, 'Click me'); }
elementEnd();
}
elementProperty(0, 'disabled', bind(ctx.isDisabled));
@ -230,7 +230,7 @@ describe('elementProperty', () => {
elementStart(0, 'button', null, [OtherDir]);
{
listener('click', ctx.onClick.bind(ctx));
text(2, 'Click me');
text(1, 'Click me');
}
elementEnd();
}
@ -271,12 +271,12 @@ describe('elementProperty', () => {
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'button', null, [IdDir]);
{ text(2, 'Click me'); }
{ text(1, 'Click me'); }
elementEnd();
container(3);
container(2);
}
elementProperty(0, 'id', bind(ctx.id1));
containerRefreshStart(3);
containerRefreshStart(2);
{
if (ctx.condition) {
if (embeddedViewStart(0)) {
@ -289,7 +289,7 @@ describe('elementProperty', () => {
} else {
if (embeddedViewStart(1)) {
elementStart(0, 'button', null, [OtherDir]);
{ text(2, 'Click me too'); }
{ text(1, 'Click me too'); }
elementEnd();
}
elementProperty(0, 'id', bind(ctx.id3));
@ -322,7 +322,8 @@ describe('elementProperty', () => {
type: MyDir,
factory: () => myDir = new MyDir(),
inputs: {role: 'role', direction: 'dir'},
outputs: {changeStream: 'change'}
outputs: {changeStream: 'change'},
exportAs: 'myDir'
});
}
@ -419,7 +420,6 @@ describe('elementProperty', () => {
it('should process attributes properly for directives with later indices', () => {
/**
* <div role="button" dir="rtl" myDir></div>
* <div role="listbox" myDirB></div>
@ -428,7 +428,7 @@ describe('elementProperty', () => {
if (cm) {
elementStart(0, 'div', ['role', 'button', 'dir', 'rtl'], [MyDir]);
elementEnd();
elementStart(2, 'div', ['role', 'listbox'], [MyDirB]);
elementStart(1, 'div', ['role', 'listbox'], [MyDirB]);
elementEnd();
}
}
@ -454,9 +454,9 @@ describe('elementProperty', () => {
if (cm) {
elementStart(0, 'div', ['role', 'listbox'], [MyDir]);
elementEnd();
container(2);
container(1);
}
containerRefreshStart(2);
containerRefreshStart(1);
{
if (ctx.condition) {
if (embeddedViewStart(0)) {
@ -495,13 +495,15 @@ describe('elementProperty', () => {
static ngComponentDef = defineComponent({
type: Comp,
tag: 'comp',
/** <div role="button" dir #dir="myDir"></div> {{ dir.role }} */
template: function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, 'div', ['role', 'button'], [MyDir]);
elementStart(0, 'div', ['role', 'button'], [MyDir], ['dir', 'myDir']);
elementEnd();
text(2);
text(1);
}
textBinding(2, bind(load<MyDir>(1).role));
// TODO: remove this loadDirective when removing MyDir
textBinding(1, bind(loadDirective<MyDir>(0).role));
},
factory: () => new Comp()
});

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {defineComponent} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
import {renderToHtml} from '../../test/render3/render_util';
@ -120,7 +120,7 @@ describe('array literals', () => {
template: function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
myComps.push(load(1));
myComps.push(loadDirective(0));
elementEnd();
}
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(e0_ff, ctx.customName))));
@ -132,7 +132,7 @@ describe('array literals', () => {
if (cm) {
elementStart(0, ParentComp);
elementEnd();
elementStart(2, ParentComp);
elementStart(1, ParentComp);
elementEnd();
}
}
@ -211,32 +211,32 @@ describe('array literals', () => {
function Template(c: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
f3Comp = load(1);
f3Comp = loadDirective(0);
elementEnd();
elementStart(1, MyComp);
f4Comp = loadDirective(1);
elementEnd();
elementStart(2, MyComp);
f4Comp = load(3);
f5Comp = loadDirective(2);
elementEnd();
elementStart(3, MyComp);
f6Comp = loadDirective(3);
elementEnd();
elementStart(4, MyComp);
f5Comp = load(5);
f7Comp = loadDirective(4);
elementEnd();
elementStart(6, MyComp);
f6Comp = load(7);
elementEnd();
elementStart(8, MyComp);
f7Comp = load(9);
elementEnd();
elementStart(10, MyComp);
f8Comp = load(11);
elementStart(5, MyComp);
f8Comp = loadDirective(5);
elementEnd();
}
elementProperty(0, 'names', bind(pureFunction3(e0_ff, c[5], c[6], c[7])));
elementProperty(2, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(4, 'names', bind(pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7])));
elementProperty(6, 'names', bind(pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(1, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(2, 'names', bind(pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7])));
elementProperty(3, 'names', bind(pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
8, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
4, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
10, 'names', bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
5, 'names', bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
}
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
@ -422,7 +422,7 @@ describe('object literals', () => {
for (let i = 0; i < 2; i++) {
if (embeddedViewStart(0)) {
elementStart(0, ObjectComp);
objectComps.push(load(1));
objectComps.push(loadDirective(0));
elementEnd();
}
elementProperty(

View File

@ -7,7 +7,7 @@
*/
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF} from '../../src/render3/di';
import {QueryList, defineComponent, detectChanges} from '../../src/render3/index';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load} from '../../src/render3/instructions';
import {container, containerRefreshEnd, containerRefreshStart, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
import {query, queryRefresh} from '../../src/render3/query';
import {createComponent, createDirective, renderComponent} from './render_util';
@ -64,9 +64,9 @@ describe('query', () => {
query(1, Child, true);
elementStart(2, Child);
{
child1 = load(3);
elementStart(4, Child);
{ child2 = load(5); }
child1 = loadDirective(0);
elementStart(3, Child);
{ child2 = loadDirective(1); }
elementEnd();
}
elementEnd();
@ -124,7 +124,7 @@ describe('query', () => {
if (cm) {
query(0, Child, false, OtherChild);
elementStart(1, 'div', null, [Child, OtherChild]);
{ otherChildInstance = load(3); }
{ otherChildInstance = loadDirective(1); }
elementEnd();
}
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
@ -418,7 +418,7 @@ describe('query', () => {
if (cm) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
elementStart(1, Child, null, null, ['foo', '']);
{ childInstance = load(2); }
{ childInstance = loadDirective(0); }
elementEnd();
}
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
@ -481,7 +481,7 @@ describe('query', () => {
if (cm) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'div', null, [Child], ['foo', 'child']);
childInstance = load(2);
childInstance = loadDirective(0);
elementEnd();
}
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
@ -510,8 +510,8 @@ describe('query', () => {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
elementStart(1, 'div', null, [Child1, Child2], ['foo', 'child1', 'bar', 'child2']);
{
child1Instance = load(2);
child2Instance = load(3);
child1Instance = loadDirective(0);
child2Instance = loadDirective(1);
}
elementEnd();
}
@ -542,7 +542,7 @@ describe('query', () => {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(1, ['bar'], true, QUERY_READ_FROM_NODE);
elementStart(2, 'div', null, [Child], ['foo', 'child', 'bar', 'child']);
{ childInstance = load(3); }
{ childInstance = loadDirective(0); }
elementEnd();
}
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.fooQuery = tmp as QueryList<any>);
@ -601,7 +601,7 @@ describe('query', () => {
if (cm) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
div = elementStart(1, 'div', null, [Child], ['foo', '', 'bar', 'child']);
{ childInstance = load(2); }
{ childInstance = loadDirective(0); }
elementEnd();
}
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);

View File

@ -8,7 +8,7 @@
import {TemplateRef, ViewContainerRef} from '../../src/core';
import {defineComponent, defineDirective, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, load, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {renderComponent, toHtml} from './render_util';
@ -40,7 +40,7 @@ describe('ViewContainerRef', () => {
container(0, [TestDirective], subTemplate);
}
containerRefreshStart(0);
cmp.testDir = load<TestDirective>(1);
cmp.testDir = loadDirective<TestDirective>(0);
containerRefreshEnd();
},
});