feat(ivy): introduce "allocHostVars" instruction as a replacement for "hostVars" field (FW-692) (#27299)
PR Close #27299
This commit is contained in:
parent
0df914e1e9
commit
a088b8c203
|
@ -146,11 +146,13 @@ describe('compiler compliance: bindings', () => {
|
||||||
selectors: [["", "hostBindingDir", ""]],
|
selectors: [["", "hostBindingDir", ""]],
|
||||||
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
|
factory: function HostBindingDir_Factory(t) { return new (t || HostBindingDir)(); },
|
||||||
hostBindings: function HostBindingDir_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function HostBindingDir_HostBindings(rf, ctx, elIndex) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind(ctx.dirId));
|
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind(ctx.dirId));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
hostVars: 1
|
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -191,11 +193,13 @@ describe('compiler compliance: bindings', () => {
|
||||||
selectors: [["host-binding-comp"]],
|
selectors: [["host-binding-comp"]],
|
||||||
factory: function HostBindingComp_Factory(t) { return new (t || HostBindingComp)(); },
|
factory: function HostBindingComp_Factory(t) { return new (t || HostBindingComp)(); },
|
||||||
hostBindings: function HostBindingComp_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function HostBindingComp_HostBindings(rf, ctx, elIndex) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(3);
|
||||||
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, ctx.id)));
|
$r3$.ɵelementProperty(elIndex, "id", $r3$.ɵbind($r3$.ɵpureFunction1(1, $ff$, ctx.id)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hostVars: 3,
|
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
template: function HostBindingComp_Template(rf, ctx) {},
|
template: function HostBindingComp_Template(rf, ctx) {},
|
||||||
|
@ -237,11 +241,13 @@ describe('compiler compliance: bindings', () => {
|
||||||
selectors: [["", "hostAttributeDir", ""]],
|
selectors: [["", "hostAttributeDir", ""]],
|
||||||
factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); },
|
factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); },
|
||||||
hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵelementAttribute(elIndex, "required", $r3$.ɵbind(ctx.required));
|
$r3$.ɵelementAttribute(elIndex, "required", $r3$.ɵbind(ctx.required));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
hostVars: 1
|
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -773,6 +773,7 @@ describe('compiler compliance: styling', () => {
|
||||||
…
|
…
|
||||||
hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(4);
|
||||||
$r3$.ɵelementStyling(_c0, _c1, $r3$.ɵdefaultStyleSanitizer, ctx);
|
$r3$.ɵelementStyling(_c0, _c1, $r3$.ɵdefaultStyleSanitizer, ctx);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
@ -831,6 +832,7 @@ describe('compiler compliance: styling', () => {
|
||||||
…
|
…
|
||||||
hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(6);
|
||||||
$r3$.ɵelementStyling(_c0, _c1, $r3$.ɵdefaultStyleSanitizer, ctx);
|
$r3$.ɵelementStyling(_c0, _c1, $r3$.ɵdefaultStyleSanitizer, ctx);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
@ -896,6 +898,7 @@ describe('compiler compliance: styling', () => {
|
||||||
…
|
…
|
||||||
function WidthDirective_HostBindings(rf, ctx, elIndex) {
|
function WidthDirective_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(2);
|
||||||
$r3$.ɵelementStyling(_c0, _c1, null, ctx);
|
$r3$.ɵelementStyling(_c0, _c1, null, ctx);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
@ -907,6 +910,7 @@ describe('compiler compliance: styling', () => {
|
||||||
…
|
…
|
||||||
function HeightDirective_HostBindings(rf, ctx, elIndex) {
|
function HeightDirective_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
$r3$.ɵallocHostVars(2);
|
||||||
$r3$.ɵelementStyling(_c2, _c3, null, ctx);
|
$r3$.ɵelementStyling(_c2, _c3, null, ctx);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
|
|
|
@ -512,6 +512,7 @@ describe('ngtsc behavioral tests', () => {
|
||||||
const hostBindingsFn = `
|
const hostBindingsFn = `
|
||||||
hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) {
|
hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
|
i0.ɵallocHostVars(3);
|
||||||
i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); });
|
i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); });
|
||||||
i0.ɵlistener("change", function FooCmp_change_HostBindingHandler($event) { return ctx.onChange(ctx.arg1, ctx.arg2, ctx.arg3); });
|
i0.ɵlistener("change", function FooCmp_change_HostBindingHandler($event) { return ctx.onChange(ctx.arg1, ctx.arg2, ctx.arg3); });
|
||||||
i0.ɵelementStyling(_c0, null, null, ctx);
|
i0.ɵelementStyling(_c0, null, null, ctx);
|
||||||
|
|
|
@ -66,6 +66,8 @@ export class Identifiers {
|
||||||
|
|
||||||
static disableBindings: o.ExternalReference = {name: 'ɵdisableBindings', moduleName: CORE};
|
static disableBindings: o.ExternalReference = {name: 'ɵdisableBindings', moduleName: CORE};
|
||||||
|
|
||||||
|
static allocHostVars: o.ExternalReference = {name: 'ɵallocHostVars', moduleName: CORE};
|
||||||
|
|
||||||
static getCurrentView: o.ExternalReference = {name: 'ɵgetCurrentView', moduleName: CORE};
|
static getCurrentView: o.ExternalReference = {name: 'ɵgetCurrentView', moduleName: CORE};
|
||||||
|
|
||||||
static restoreView: o.ExternalReference = {name: 'ɵrestoreView', moduleName: CORE};
|
static restoreView: o.ExternalReference = {name: 'ɵrestoreView', moduleName: CORE};
|
||||||
|
|
|
@ -62,8 +62,8 @@ function baseDirectiveFields(
|
||||||
|
|
||||||
definitionMap.set('contentQueriesRefresh', createContentQueriesRefreshFunction(meta));
|
definitionMap.set('contentQueriesRefresh', createContentQueriesRefreshFunction(meta));
|
||||||
|
|
||||||
// Initialize hostVars to number of bound host properties (interpolations illegal)
|
// Initialize hostVarsCount to number of bound host properties (interpolations illegal)
|
||||||
let hostVars = Object.keys(meta.host.properties).length;
|
const hostVarsCount = Object.keys(meta.host.properties).length;
|
||||||
|
|
||||||
const elVarExp = o.variable('elIndex');
|
const elVarExp = o.variable('elIndex');
|
||||||
const contextVarExp = o.variable(CONTEXT_NAME);
|
const contextVarExp = o.variable(CONTEXT_NAME);
|
||||||
|
@ -94,18 +94,9 @@ function baseDirectiveFields(
|
||||||
|
|
||||||
// e.g. `hostBindings: (rf, ctx, elIndex) => { ... }
|
// e.g. `hostBindings: (rf, ctx, elIndex) => { ... }
|
||||||
definitionMap.set(
|
definitionMap.set(
|
||||||
'hostBindings', createHostBindingsFunction(
|
'hostBindings',
|
||||||
meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool,
|
createHostBindingsFunction(
|
||||||
(slots: number) => {
|
meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool, hostVarsCount));
|
||||||
const originalSlots = hostVars;
|
|
||||||
hostVars += slots;
|
|
||||||
return originalSlots;
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (hostVars) {
|
|
||||||
// e.g. `hostVars: 2
|
|
||||||
definitionMap.set('hostVars', o.literal(hostVars));
|
|
||||||
}
|
|
||||||
|
|
||||||
// e.g 'inputs: {a: 'a'}`
|
// e.g 'inputs: {a: 'a'}`
|
||||||
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs));
|
definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs));
|
||||||
|
@ -645,12 +636,12 @@ function createViewQueriesFunction(
|
||||||
function createHostBindingsFunction(
|
function createHostBindingsFunction(
|
||||||
meta: R3DirectiveMetadata, elVarExp: o.ReadVarExpr, bindingContext: o.ReadVarExpr,
|
meta: R3DirectiveMetadata, elVarExp: o.ReadVarExpr, bindingContext: o.ReadVarExpr,
|
||||||
styleBuilder: StylingBuilder, bindingParser: BindingParser, constantPool: ConstantPool,
|
styleBuilder: StylingBuilder, bindingParser: BindingParser, constantPool: ConstantPool,
|
||||||
allocatePureFunctionSlots: (slots: number) => number): o.Expression|null {
|
hostVarsCount: number): o.Expression|null {
|
||||||
const createStatements: o.Statement[] = [];
|
const createStatements: o.Statement[] = [];
|
||||||
const updateStatements: o.Statement[] = [];
|
const updateStatements: o.Statement[] = [];
|
||||||
|
|
||||||
|
let totalHostVarsCount = hostVarsCount;
|
||||||
const hostBindingSourceSpan = meta.typeSourceSpan;
|
const hostBindingSourceSpan = meta.typeSourceSpan;
|
||||||
|
|
||||||
const directiveSummary = metadataAsSummary(meta);
|
const directiveSummary = metadataAsSummary(meta);
|
||||||
|
|
||||||
// Calculate host event bindings
|
// Calculate host event bindings
|
||||||
|
@ -670,9 +661,13 @@ function createHostBindingsFunction(
|
||||||
};
|
};
|
||||||
|
|
||||||
if (bindings) {
|
if (bindings) {
|
||||||
|
const hostVarsCountFn = (numSlots: number): number => {
|
||||||
|
totalHostVarsCount += numSlots;
|
||||||
|
return hostVarsCount;
|
||||||
|
};
|
||||||
const valueConverter = new ValueConverter(
|
const valueConverter = new ValueConverter(
|
||||||
constantPool,
|
constantPool,
|
||||||
/* new nodes are illegal here */ () => error('Unexpected node'), allocatePureFunctionSlots,
|
/* new nodes are illegal here */ () => error('Unexpected node'), hostVarsCountFn,
|
||||||
/* pipes are illegal here */ () => error('Unexpected pipe'));
|
/* pipes are illegal here */ () => error('Unexpected pipe'));
|
||||||
|
|
||||||
for (const binding of bindings) {
|
for (const binding of bindings) {
|
||||||
|
@ -716,6 +711,11 @@ function createHostBindingsFunction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalHostVarsCount) {
|
||||||
|
createStatements.unshift(
|
||||||
|
o.importExpr(R3.allocHostVars).callFn([o.literal(totalHostVarsCount)]).toStmt());
|
||||||
|
}
|
||||||
|
|
||||||
if (createStatements.length > 0 || updateStatements.length > 0) {
|
if (createStatements.length > 0 || updateStatements.length > 0) {
|
||||||
const hostBindingsFnName = meta.name ? `${meta.name}_HostBindings` : null;
|
const hostBindingsFnName = meta.name ? `${meta.name}_HostBindings` : null;
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
|
|
|
@ -85,6 +85,7 @@ export {
|
||||||
reference as ɵreference,
|
reference as ɵreference,
|
||||||
enableBindings as ɵenableBindings,
|
enableBindings as ɵenableBindings,
|
||||||
disableBindings as ɵdisableBindings,
|
disableBindings as ɵdisableBindings,
|
||||||
|
allocHostVars as ɵallocHostVars,
|
||||||
elementAttribute as ɵelementAttribute,
|
elementAttribute as ɵelementAttribute,
|
||||||
elementContainerStart as ɵelementContainerStart,
|
elementContainerStart as ɵelementContainerStart,
|
||||||
elementContainerEnd as ɵelementContainerEnd,
|
elementContainerEnd as ɵelementContainerEnd,
|
||||||
|
|
|
@ -17,13 +17,13 @@ import {getComponentDef} from './definition';
|
||||||
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
|
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
|
||||||
import {publishDefaultGlobalUtils} from './global_utils';
|
import {publishDefaultGlobalUtils} from './global_utils';
|
||||||
import {queueInitHooks, queueLifecycleHooks} from './hooks';
|
import {queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {CLEAN_PROMISE, createLView, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, prefillHostVars, queueComponentIndexForCheck, refreshDescendantViews} from './instructions';
|
import {CLEAN_PROMISE, createLView, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, queueComponentIndexForCheck, refreshDescendantViews} from './instructions';
|
||||||
import {ComponentDef, ComponentType} from './interfaces/definition';
|
import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition';
|
||||||
import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
|
import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node';
|
||||||
import {PlayerHandler} from './interfaces/player';
|
import {PlayerHandler} from './interfaces/player';
|
||||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
|
import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
|
||||||
import {enterView, leaveView, resetComponentState} from './state';
|
import {enterView, getPreviousOrParentTNode, leaveView, resetComponentState, setCurrentDirectiveDef} from './state';
|
||||||
import {defaultScheduler, getRootView, readPatchedLView, stringify} from './util';
|
import {defaultScheduler, getRootView, readPatchedLView, stringify} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,7 +195,13 @@ export function createRootComponent<T>(
|
||||||
|
|
||||||
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
|
hostFeatures && hostFeatures.forEach((feature) => feature(component, componentDef));
|
||||||
|
|
||||||
if (tView.firstTemplatePass) prefillHostVars(tView, rootView, componentDef.hostVars);
|
if (tView.firstTemplatePass && componentDef.hostBindings) {
|
||||||
|
const rootTNode = getPreviousOrParentTNode();
|
||||||
|
setCurrentDirectiveDef(componentDef);
|
||||||
|
componentDef.hostBindings(RenderFlags.Create, component, rootTNode.index);
|
||||||
|
setCurrentDirectiveDef(null);
|
||||||
|
}
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,14 +73,6 @@ export function defineComponent<T>(componentDefinition: {
|
||||||
*/
|
*/
|
||||||
vars: number;
|
vars: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of host bindings (including pure fn bindings) in this component.
|
|
||||||
*
|
|
||||||
* Used to calculate the length of the LView array for the *parent* component
|
|
||||||
* of this component.
|
|
||||||
*/
|
|
||||||
hostVars?: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static attributes to set on host element.
|
* Static attributes to set on host element.
|
||||||
*
|
*
|
||||||
|
@ -262,7 +254,6 @@ export function defineComponent<T>(componentDefinition: {
|
||||||
providersResolver: null,
|
providersResolver: null,
|
||||||
consts: componentDefinition.consts,
|
consts: componentDefinition.consts,
|
||||||
vars: componentDefinition.vars,
|
vars: componentDefinition.vars,
|
||||||
hostVars: componentDefinition.hostVars || 0,
|
|
||||||
factory: componentDefinition.factory,
|
factory: componentDefinition.factory,
|
||||||
template: componentDefinition.template || null !,
|
template: componentDefinition.template || null !,
|
||||||
hostBindings: componentDefinition.hostBindings || null,
|
hostBindings: componentDefinition.hostBindings || null,
|
||||||
|
@ -586,14 +577,6 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
|
||||||
*/
|
*/
|
||||||
features?: DirectiveDefFeature[];
|
features?: DirectiveDefFeature[];
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of host bindings (including pure fn bindings) in this directive.
|
|
||||||
*
|
|
||||||
* Used to calculate the length of the LView array for the *parent* component
|
|
||||||
* of this directive.
|
|
||||||
*/
|
|
||||||
hostVars?: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function executed by the parent template to allow child directive to apply host bindings.
|
* Function executed by the parent template to allow child directive to apply host bindings.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -76,7 +76,6 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
|
||||||
superHostBindings(rf, ctx, elementIndex);
|
superHostBindings(rf, ctx, elementIndex);
|
||||||
prevHostBindings(rf, ctx, elementIndex);
|
prevHostBindings(rf, ctx, elementIndex);
|
||||||
};
|
};
|
||||||
(definition as any).hostVars += superDef.hostVars;
|
|
||||||
} else {
|
} else {
|
||||||
definition.hostBindings = superHostBindings;
|
definition.hostBindings = superHostBindings;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ export {CssSelectorList} from './interfaces/projection';
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
export {
|
export {
|
||||||
|
allocHostVars,
|
||||||
bind,
|
bind,
|
||||||
interpolation1,
|
interpolation1,
|
||||||
interpolation2,
|
interpolation2,
|
||||||
|
|
|
@ -16,7 +16,6 @@ import {Sanitizer} from '../sanitization/security';
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
||||||
import {noop} from '../util/noop';
|
|
||||||
|
|
||||||
import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert';
|
import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert';
|
||||||
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings';
|
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings';
|
||||||
|
@ -38,7 +37,7 @@ import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLA
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getLViewChild, getRenderParent, insertView, removeView} from './node_manipulation';
|
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getLViewChild, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCreationMode, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state';
|
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCreationMode, getCurrentDirectiveDef, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state';
|
||||||
import {createStylingContextTemplate, renderStyleAndClassBindings, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
|
import {createStylingContextTemplate, renderStyleAndClassBindings, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
|
||||||
import {BoundPlayerFactory} from './styling/player_factory';
|
import {BoundPlayerFactory} from './styling/player_factory';
|
||||||
import {getStylingContext} from './styling/util';
|
import {getStylingContext} from './styling/util';
|
||||||
|
@ -46,7 +45,6 @@ import {NO_CHANGE} from './tokens';
|
||||||
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, loadInternal, readElementValue, readPatchedLView, stringify} from './util';
|
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, loadInternal, readElementValue, readPatchedLView, stringify} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A permanent marker promise which signifies that the current CD tree is
|
* A permanent marker promise which signifies that the current CD tree is
|
||||||
* clean.
|
* clean.
|
||||||
|
@ -125,10 +123,12 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
||||||
setBindingRoot(bindingRootIndex);
|
setBindingRoot(bindingRootIndex);
|
||||||
} else {
|
} else {
|
||||||
// If it's not a number, it's a host binding function that needs to be executed.
|
// If it's not a number, it's a host binding function that needs to be executed.
|
||||||
viewData[BINDING_INDEX] = bindingRootIndex;
|
if (instruction !== null) {
|
||||||
instruction(
|
viewData[BINDING_INDEX] = bindingRootIndex;
|
||||||
RenderFlags.Update, readElementValue(viewData[currentDirectiveIndex]),
|
instruction(
|
||||||
currentElementIndex);
|
RenderFlags.Update, readElementValue(viewData[currentDirectiveIndex]),
|
||||||
|
currentElementIndex);
|
||||||
|
}
|
||||||
currentDirectiveIndex++;
|
currentDirectiveIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,6 +613,7 @@ function createDirectivesAndLocals(
|
||||||
previousOrParentTNode, localRefs || null);
|
previousOrParentTNode, localRefs || null);
|
||||||
}
|
}
|
||||||
instantiateAllDirectives(tView, viewData, previousOrParentTNode);
|
instantiateAllDirectives(tView, viewData, previousOrParentTNode);
|
||||||
|
invokeDirectivesHostBindings(tView, viewData, previousOrParentTNode);
|
||||||
saveResolvedLocalsInData(viewData, previousOrParentTNode, localRefExtractor);
|
saveResolvedLocalsInData(viewData, previousOrParentTNode, localRefExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,7 +1416,6 @@ function resolveDirectives(
|
||||||
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle.
|
// Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle.
|
||||||
ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only');
|
ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only');
|
||||||
const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null;
|
const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null;
|
||||||
let totalHostVars = 0;
|
|
||||||
if (directives) {
|
if (directives) {
|
||||||
initNodeFlags(tNode, tView.data.length, directives.length);
|
initNodeFlags(tNode, tView.data.length, directives.length);
|
||||||
// When the same token is provided by several directives on the same node, some rules apply in
|
// When the same token is provided by several directives on the same node, some rules apply in
|
||||||
|
@ -1435,7 +1435,6 @@ function resolveDirectives(
|
||||||
const directiveDefIdx = tView.data.length;
|
const directiveDefIdx = tView.data.length;
|
||||||
baseResolveDirective(tView, viewData, def, def.factory);
|
baseResolveDirective(tView, viewData, def, def.factory);
|
||||||
|
|
||||||
totalHostVars += def.hostVars;
|
|
||||||
saveNameToExportMap(tView.data !.length - 1, def, exportsMap);
|
saveNameToExportMap(tView.data !.length - 1, def, exportsMap);
|
||||||
|
|
||||||
// Init hooks are queued now so ngOnInit is called in host components before
|
// Init hooks are queued now so ngOnInit is called in host components before
|
||||||
|
@ -1444,7 +1443,6 @@ function resolveDirectives(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
||||||
prefillHostVars(tView, viewData, totalHostVars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1468,6 +1466,31 @@ function instantiateAllDirectives(tView: TView, viewData: LView, previousOrParen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function invokeDirectivesHostBindings(tView: TView, viewData: LView, previousOrParentTNode: TNode) {
|
||||||
|
const start = previousOrParentTNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
|
||||||
|
const end = start + (previousOrParentTNode.flags & TNodeFlags.DirectiveCountMask);
|
||||||
|
const expando = tView.expandoInstructions !;
|
||||||
|
const firstTemplatePass = getFirstTemplatePass();
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
|
const def = tView.data[i] as DirectiveDef<any>;
|
||||||
|
const directive = viewData[i];
|
||||||
|
if (def.hostBindings) {
|
||||||
|
const previousExpandoLength = expando.length;
|
||||||
|
setCurrentDirectiveDef(def);
|
||||||
|
def.hostBindings !(RenderFlags.Create, directive, previousOrParentTNode.index);
|
||||||
|
setCurrentDirectiveDef(null);
|
||||||
|
// `hostBindings` function may or may not contain `allocHostVars` call
|
||||||
|
// (e.g. it may not if it only contains host listeners), so we need to check whether
|
||||||
|
// `expandoInstructions` has changed and if not - we push `null` to keep indices in sync
|
||||||
|
if (previousExpandoLength === expando.length && firstTemplatePass) {
|
||||||
|
expando.push(null);
|
||||||
|
}
|
||||||
|
} else if (firstTemplatePass) {
|
||||||
|
expando.push(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new block in TView.expandoInstructions for this node.
|
* Generates a new block in TView.expandoInstructions for this node.
|
||||||
*
|
*
|
||||||
|
@ -1492,7 +1515,9 @@ export function generateExpandoInstructionBlock(
|
||||||
* after directives are matched (so all directives are saved, then bindings).
|
* after directives are matched (so all directives are saved, then bindings).
|
||||||
* Because we are updating the blueprint, we only need to do this once.
|
* Because we are updating the blueprint, we only need to do this once.
|
||||||
*/
|
*/
|
||||||
export function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): void {
|
function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): void {
|
||||||
|
ngDevMode &&
|
||||||
|
assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.');
|
||||||
for (let i = 0; i < totalHostVars; i++) {
|
for (let i = 0; i < totalHostVars; i++) {
|
||||||
lView.push(NO_CHANGE);
|
lView.push(NO_CHANGE);
|
||||||
tView.blueprint.push(NO_CHANGE);
|
tView.blueprint.push(NO_CHANGE);
|
||||||
|
@ -1534,10 +1559,6 @@ function postProcessBaseDirective<T>(
|
||||||
'directives should be created before any bindings');
|
'directives should be created before any bindings');
|
||||||
ngDevMode && assertPreviousIsParent(getIsParent());
|
ngDevMode && assertPreviousIsParent(getIsParent());
|
||||||
|
|
||||||
if (def.hostBindings) {
|
|
||||||
def.hostBindings(RenderFlags.Create, directive, previousOrParentTNode.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
attachPatchData(directive, lView);
|
attachPatchData(directive, lView);
|
||||||
if (native) {
|
if (native) {
|
||||||
attachPatchData(native, lView);
|
attachPatchData(native, lView);
|
||||||
|
@ -1594,13 +1615,21 @@ export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void
|
||||||
(tView.components || (tView.components = [])).push(previousOrParentTNode.index);
|
(tView.components || (tView.components = [])).push(previousOrParentTNode.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stores index of directive and host element so it will be queued for binding refresh during CD.
|
/**
|
||||||
|
* Stores host binding fn and number of host vars so it will be queued for binding refresh during
|
||||||
|
* CD.
|
||||||
*/
|
*/
|
||||||
function queueHostBindingForCheck(tView: TView, def: DirectiveDef<any>| ComponentDef<any>): void {
|
function queueHostBindingForCheck(
|
||||||
|
tView: TView, def: DirectiveDef<any>| ComponentDef<any>, hostVars: number): void {
|
||||||
ngDevMode &&
|
ngDevMode &&
|
||||||
assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.');
|
assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.');
|
||||||
tView.expandoInstructions !.push(def.hostBindings || noop);
|
const expando = tView.expandoInstructions !;
|
||||||
if (def.hostVars) tView.expandoInstructions !.push(def.hostVars);
|
// check whether a given `hostBindings` function already exists in expandoInstructions,
|
||||||
|
// which can happen in case directive definition was extended from base definition (as a part of
|
||||||
|
// the `InheritDefinitionFeature` logic)
|
||||||
|
if (expando.length < 2 || expando[expando.length - 2] !== def.hostBindings) {
|
||||||
|
expando.push(def.hostBindings !, hostVars);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Caches local names and their matching directive indices for query and template lookups. */
|
/** Caches local names and their matching directive indices for query and template lookups. */
|
||||||
|
@ -1661,8 +1690,6 @@ function baseResolveDirective<T>(
|
||||||
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
|
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
|
||||||
tView.blueprint.push(nodeInjectorFactory);
|
tView.blueprint.push(nodeInjectorFactory);
|
||||||
viewData.push(nodeInjectorFactory);
|
viewData.push(nodeInjectorFactory);
|
||||||
|
|
||||||
queueHostBindingForCheck(tView, def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addComponentLogic<T>(
|
function addComponentLogic<T>(
|
||||||
|
@ -2495,6 +2522,19 @@ export function bind<T>(value: T): T|NO_CHANGE {
|
||||||
return bindingUpdated(lView, lView[BINDING_INDEX]++, value) ? value : NO_CHANGE;
|
return bindingUpdated(lView, lView[BINDING_INDEX]++, value) ? value : NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates the necessary amount of slots for host vars.
|
||||||
|
*
|
||||||
|
* @param count Amount of vars to be allocated
|
||||||
|
*/
|
||||||
|
export function allocHostVars(count: number): void {
|
||||||
|
if (!getFirstTemplatePass()) return;
|
||||||
|
const lView = getLView();
|
||||||
|
const tView = lView[TVIEW];
|
||||||
|
queueHostBindingForCheck(tView, getCurrentDirectiveDef() !, count);
|
||||||
|
prefillHostVars(tView, lView, count);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create interpolation bindings with a variable number of expressions.
|
* Create interpolation bindings with a variable number of expressions.
|
||||||
*
|
*
|
||||||
|
|
|
@ -136,14 +136,6 @@ export interface DirectiveDef<T> extends BaseDef<T> {
|
||||||
/** Refreshes content queries associated with directives in a given view */
|
/** Refreshes content queries associated with directives in a given view */
|
||||||
contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null;
|
contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null;
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of host bindings (including pure fn bindings) in this directive/component.
|
|
||||||
*
|
|
||||||
* Used to calculate the length of the LView array for the *parent* component
|
|
||||||
* of this directive/component.
|
|
||||||
*/
|
|
||||||
readonly hostVars: number;
|
|
||||||
|
|
||||||
/** Refreshes host bindings on the associated directive. */
|
/** Refreshes host bindings on the associated directive. */
|
||||||
hostBindings: HostBindingsFunction<T>|null;
|
hostBindings: HostBindingsFunction<T>|null;
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,7 @@ export interface TView {
|
||||||
*
|
*
|
||||||
* See VIEW_DATA.md for more information.
|
* See VIEW_DATA.md for more information.
|
||||||
*/
|
*/
|
||||||
expandoInstructions: (number|HostBindingsFunction<any>)[]|null;
|
expandoInstructions: (number|HostBindingsFunction<any>|null)[]|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full registry of directives and components that may be found in this view.
|
* Full registry of directives and components that may be found in this view.
|
||||||
|
|
|
@ -46,6 +46,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵnamespaceSVG': r3.namespaceSVG,
|
'ɵnamespaceSVG': r3.namespaceSVG,
|
||||||
'ɵenableBindings': r3.enableBindings,
|
'ɵenableBindings': r3.enableBindings,
|
||||||
'ɵdisableBindings': r3.disableBindings,
|
'ɵdisableBindings': r3.disableBindings,
|
||||||
|
'ɵallocHostVars': r3.allocHostVars,
|
||||||
'ɵelementStart': r3.elementStart,
|
'ɵelementStart': r3.elementStart,
|
||||||
'ɵelementEnd': r3.elementEnd,
|
'ɵelementEnd': r3.elementEnd,
|
||||||
'ɵelement': r3.element,
|
'ɵelement': r3.element,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import {assertDefined} from './assert';
|
import {assertDefined} from './assert';
|
||||||
import {executeHooks} from './hooks';
|
import {executeHooks} from './hooks';
|
||||||
|
import {ComponentDef, DirectiveDef} from './interfaces/definition';
|
||||||
import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node';
|
import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LView, LViewFlags, OpaqueViewState, QUERIES, TVIEW} from './interfaces/view';
|
import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LView, LViewFlags, OpaqueViewState, QUERIES, TVIEW} from './interfaces/view';
|
||||||
|
@ -34,6 +35,17 @@ export function decreaseElementDepthCount() {
|
||||||
elementDepthCount--;
|
elementDepthCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let currentDirectiveDef: DirectiveDef<any>|ComponentDef<any>|null = null;
|
||||||
|
|
||||||
|
export function getCurrentDirectiveDef(): DirectiveDef<any>|ComponentDef<any>|null {
|
||||||
|
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||||
|
return currentDirectiveDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCurrentDirectiveDef(def: DirectiveDef<any>| ComponentDef<any>| null): void {
|
||||||
|
currentDirectiveDef = def;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores whether directives should be matched to elements.
|
* Stores whether directives should be matched to elements.
|
||||||
*
|
*
|
||||||
|
|
|
@ -842,6 +842,9 @@
|
||||||
{
|
{
|
||||||
"name": "invertObject"
|
"name": "invertObject"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "invokeDirectivesHostBindings"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "isClassBased"
|
"name": "isClassBased"
|
||||||
},
|
},
|
||||||
|
@ -968,9 +971,6 @@
|
||||||
{
|
{
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "noop"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "onChangesWrapper"
|
"name": "onChangesWrapper"
|
||||||
},
|
},
|
||||||
|
@ -983,9 +983,6 @@
|
||||||
{
|
{
|
||||||
"name": "postProcessDirective"
|
"name": "postProcessDirective"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "prefillHostVars"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "prepareInitialFlag"
|
"name": "prepareInitialFlag"
|
||||||
},
|
},
|
||||||
|
@ -1001,9 +998,6 @@
|
||||||
{
|
{
|
||||||
"name": "queueDestroyHooks"
|
"name": "queueDestroyHooks"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "queueHostBindingForCheck"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "queueInitHooks"
|
"name": "queueInitHooks"
|
||||||
},
|
},
|
||||||
|
@ -1091,6 +1085,9 @@
|
||||||
{
|
{
|
||||||
"name": "setContextPlayersDirty"
|
"name": "setContextPlayersDirty"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setCurrentDirectiveDef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setDirty"
|
"name": "setDirty"
|
||||||
},
|
},
|
||||||
|
|
|
@ -377,24 +377,15 @@
|
||||||
{
|
{
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "noop"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "onChangesWrapper"
|
"name": "onChangesWrapper"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "postProcessBaseDirective"
|
"name": "postProcessBaseDirective"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "prefillHostVars"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "queueComponentIndexForCheck"
|
"name": "queueComponentIndexForCheck"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "queueHostBindingForCheck"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "readElementValue"
|
"name": "readElementValue"
|
||||||
},
|
},
|
||||||
|
@ -431,6 +422,9 @@
|
||||||
{
|
{
|
||||||
"name": "setBindingRoot"
|
"name": "setBindingRoot"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setCurrentDirectiveDef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setFirstTemplatePass"
|
"name": "setFirstTemplatePass"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1142,9 +1142,6 @@
|
||||||
{
|
{
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "noop"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "noop$1"
|
"name": "noop$1"
|
||||||
},
|
},
|
||||||
|
@ -1184,9 +1181,6 @@
|
||||||
{
|
{
|
||||||
"name": "postProcessBaseDirective"
|
"name": "postProcessBaseDirective"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "prefillHostVars"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "projectionNodeStack"
|
"name": "projectionNodeStack"
|
||||||
},
|
},
|
||||||
|
@ -1208,9 +1202,6 @@
|
||||||
{
|
{
|
||||||
"name": "queueDestroyHooks"
|
"name": "queueDestroyHooks"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "queueHostBindingForCheck"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "queueInitHooks"
|
"name": "queueInitHooks"
|
||||||
},
|
},
|
||||||
|
@ -1292,6 +1283,9 @@
|
||||||
{
|
{
|
||||||
"name": "setCheckNoChangesMode"
|
"name": "setCheckNoChangesMode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setCurrentDirectiveDef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setCurrentInjector"
|
"name": "setCurrentInjector"
|
||||||
},
|
},
|
||||||
|
|
|
@ -872,6 +872,9 @@
|
||||||
{
|
{
|
||||||
"name": "invertObject"
|
"name": "invertObject"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "invokeDirectivesHostBindings"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "isComponent"
|
"name": "isComponent"
|
||||||
},
|
},
|
||||||
|
@ -986,9 +989,6 @@
|
||||||
{
|
{
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "noop"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "onChangesWrapper"
|
"name": "onChangesWrapper"
|
||||||
},
|
},
|
||||||
|
@ -1001,9 +1001,6 @@
|
||||||
{
|
{
|
||||||
"name": "postProcessDirective"
|
"name": "postProcessDirective"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "prefillHostVars"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "prepareInitialFlag"
|
"name": "prepareInitialFlag"
|
||||||
},
|
},
|
||||||
|
@ -1019,9 +1016,6 @@
|
||||||
{
|
{
|
||||||
"name": "queueDestroyHooks"
|
"name": "queueDestroyHooks"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "queueHostBindingForCheck"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "queueInitHooks"
|
"name": "queueInitHooks"
|
||||||
},
|
},
|
||||||
|
@ -1112,6 +1106,9 @@
|
||||||
{
|
{
|
||||||
"name": "setContextPlayersDirty"
|
"name": "setContextPlayersDirty"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setCurrentDirectiveDef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setDirty"
|
"name": "setDirty"
|
||||||
},
|
},
|
||||||
|
|
|
@ -2105,6 +2105,9 @@
|
||||||
{
|
{
|
||||||
"name": "invertObject"
|
"name": "invertObject"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "invokeDirectivesHostBindings"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "isArray"
|
"name": "isArray"
|
||||||
},
|
},
|
||||||
|
@ -2333,9 +2336,6 @@
|
||||||
{
|
{
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "noop"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "noop$1"
|
"name": "noop$1"
|
||||||
},
|
},
|
||||||
|
@ -2399,9 +2399,6 @@
|
||||||
{
|
{
|
||||||
"name": "postProcessDirective"
|
"name": "postProcessDirective"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "prefillHostVars"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "prepareInitialFlag"
|
"name": "prepareInitialFlag"
|
||||||
},
|
},
|
||||||
|
@ -2426,9 +2423,6 @@
|
||||||
{
|
{
|
||||||
"name": "queueDestroyHooks"
|
"name": "queueDestroyHooks"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "queueHostBindingForCheck"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "queueInitHooks"
|
"name": "queueInitHooks"
|
||||||
},
|
},
|
||||||
|
@ -2546,6 +2540,9 @@
|
||||||
{
|
{
|
||||||
"name": "setContextPlayersDirty"
|
"name": "setContextPlayersDirty"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setCurrentDirectiveDef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setCurrentInjector"
|
"name": "setCurrentInjector"
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Inject, InjectionToken} from '../../src/core';
|
import {Inject, InjectionToken} from '../../src/core';
|
||||||
import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, bind, defineBase, defineComponent, defineDirective, directiveInject, element, elementProperty, load} from '../../src/render3/index';
|
import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, allocHostVars, bind, defineBase, defineComponent, defineDirective, directiveInject, element, elementProperty, load} from '../../src/render3/index';
|
||||||
|
|
||||||
import {ComponentFixture, createComponent} from './render_util';
|
import {ComponentFixture, createComponent} from './render_util';
|
||||||
|
|
||||||
|
@ -309,11 +309,13 @@ describe('InheritDefinitionFeature', () => {
|
||||||
type: SuperDirective,
|
type: SuperDirective,
|
||||||
selectors: [['', 'superDir', '']],
|
selectors: [['', 'superDir', '']],
|
||||||
hostBindings: (rf: RenderFlags, ctx: SuperDirective, elementIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: SuperDirective, elementIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elementIndex, 'id', bind(ctx.id));
|
elementProperty(elementIndex, 'id', bind(ctx.id));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hostVars: 1,
|
|
||||||
factory: () => new SuperDirective(),
|
factory: () => new SuperDirective(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -325,11 +327,13 @@ describe('InheritDefinitionFeature', () => {
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
selectors: [['', 'subDir', '']],
|
selectors: [['', 'subDir', '']],
|
||||||
hostBindings: (rf: RenderFlags, ctx: SubDirective, elementIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: SubDirective, elementIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elementIndex, 'title', bind(ctx.title));
|
elementProperty(elementIndex, 'title', bind(ctx.title));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hostVars: 1,
|
|
||||||
factory: () => subDir = new SubDirective(),
|
factory: () => subDir = new SubDirective(),
|
||||||
features: [InheritDefinitionFeature]
|
features: [InheritDefinitionFeature]
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
|
||||||
import {ProvidersFeature, defineDirective, elementProperty, load, templateRefExtractor} from '../../src/render3/index';
|
import {ProvidersFeature, defineDirective, elementProperty, load, templateRefExtractor} from '../../src/render3/index';
|
||||||
|
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLView, createTView, directiveInject, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, injectAttribute, interpolation2, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLView, createTView, directiveInject, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, injectAttribute, interpolation2, projection, projectionDef, reference, template, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
||||||
import {isProceduralRenderer, RElement} from '../../src/render3/interfaces/renderer';
|
import {isProceduralRenderer, RElement} from '../../src/render3/interfaces/renderer';
|
||||||
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
||||||
import {getNativeByIndex} from '../../src/render3/util';
|
import {getNativeByIndex} from '../../src/render3/util';
|
||||||
|
@ -654,8 +654,10 @@ describe('di', () => {
|
||||||
type: HostBindingDir,
|
type: HostBindingDir,
|
||||||
selectors: [['', 'hostBindingDir', '']],
|
selectors: [['', 'hostBindingDir', '']],
|
||||||
factory: () => hostBindingDir = new HostBindingDir(),
|
factory: () => hostBindingDir = new HostBindingDir(),
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elementIndex, 'id', bind(ctx.id));
|
elementProperty(elementIndex, 'id', bind(ctx.id));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {ElementRef, EventEmitter} from '@angular/core';
|
import {ElementRef, EventEmitter} from '@angular/core';
|
||||||
|
|
||||||
import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature, NgOnChangesFeature, QueryList} from '../../src/render3/index';
|
import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature, NgOnChangesFeature, QueryList} from '../../src/render3/index';
|
||||||
import {bind, directiveInject, element, elementEnd, elementProperty, elementStart, load, text, textBinding, loadQueryList, registerContentQuery} from '../../src/render3/instructions';
|
import {allocHostVars, bind, directiveInject, element, elementEnd, elementProperty, elementStart, listener, load, text, textBinding, loadQueryList, registerContentQuery} from '../../src/render3/instructions';
|
||||||
import {query, queryRefresh} from '../../src/render3/query';
|
import {query, queryRefresh} from '../../src/render3/query';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
||||||
|
@ -49,8 +49,10 @@ describe('host bindings', () => {
|
||||||
type: HostBindingDir,
|
type: HostBindingDir,
|
||||||
selectors: [['', 'hostBindingDir', '']],
|
selectors: [['', 'hostBindingDir', '']],
|
||||||
factory: () => hostBindingDir = new HostBindingDir(),
|
factory: () => hostBindingDir = new HostBindingDir(),
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elementIndex, 'id', bind(ctx.id));
|
elementProperty(elementIndex, 'id', bind(ctx.id));
|
||||||
}
|
}
|
||||||
|
@ -68,8 +70,10 @@ describe('host bindings', () => {
|
||||||
factory: () => new HostBindingComp(),
|
factory: () => new HostBindingComp(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(ctx.id));
|
elementProperty(elIndex, 'id', bind(ctx.id));
|
||||||
}
|
}
|
||||||
|
@ -89,8 +93,10 @@ describe('host bindings', () => {
|
||||||
type: Directive,
|
type: Directive,
|
||||||
selectors: [['', 'dir', '']],
|
selectors: [['', 'dir', '']],
|
||||||
factory: () => directiveInstance = new Directive,
|
factory: () => directiveInstance = new Directive,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elementIndex, 'className', bind(ctx.klass));
|
elementProperty(elementIndex, 'className', bind(ctx.klass));
|
||||||
}
|
}
|
||||||
|
@ -139,8 +145,10 @@ describe('host bindings', () => {
|
||||||
() => new CompWithProviders(directiveInject(ServiceOne), directiveInject(ServiceTwo)),
|
() => new CompWithProviders(directiveInject(ServiceOne), directiveInject(ServiceTwo)),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: CompWithProviders, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: CompWithProviders, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(ctx.id));
|
elementProperty(elIndex, 'id', bind(ctx.id));
|
||||||
}
|
}
|
||||||
|
@ -173,8 +181,10 @@ describe('host bindings', () => {
|
||||||
factory: () => new HostTitleComp(),
|
factory: () => new HostTitleComp(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostTitleComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostTitleComp, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'title', bind(ctx.title));
|
elementProperty(elIndex, 'title', bind(ctx.title));
|
||||||
}
|
}
|
||||||
|
@ -207,6 +217,66 @@ describe('host bindings', () => {
|
||||||
expect(hostBindingDiv.id).toEqual('bar');
|
expect(hostBindingDiv.id).toEqual('bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support consecutive components with host bindings', () => {
|
||||||
|
let comps: HostBindingComp[] = [];
|
||||||
|
|
||||||
|
class HostBindingComp {
|
||||||
|
// @HostBinding()
|
||||||
|
id = 'blue';
|
||||||
|
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: HostBindingComp,
|
||||||
|
selectors: [['host-binding-comp']],
|
||||||
|
factory: () => {
|
||||||
|
const comp = new HostBindingComp();
|
||||||
|
comps.push(comp);
|
||||||
|
return comp;
|
||||||
|
},
|
||||||
|
consts: 0,
|
||||||
|
vars: 0,
|
||||||
|
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
elementProperty(elIndex, 'id', bind(ctx.id));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: (rf: RenderFlags, ctx: HostBindingComp) => {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <host-binding-comp></host-binding-comp>
|
||||||
|
* <host-binding-comp></host-binding-comp>
|
||||||
|
* */
|
||||||
|
const App = createComponent('app', (rf: RenderFlags, ctx: any) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'host-binding-comp');
|
||||||
|
element(1, 'host-binding-comp');
|
||||||
|
}
|
||||||
|
}, 2, 0, [HostBindingComp]);
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(App);
|
||||||
|
const hostBindingEls =
|
||||||
|
fixture.hostElement.querySelectorAll('host-binding-comp') as NodeListOf<HTMLElement>;
|
||||||
|
|
||||||
|
expect(hostBindingEls.length).toBe(2);
|
||||||
|
|
||||||
|
comps[0].id = 'red';
|
||||||
|
fixture.update();
|
||||||
|
expect(hostBindingEls[0].id).toBe('red');
|
||||||
|
|
||||||
|
// second element should not be affected
|
||||||
|
expect(hostBindingEls[1].id).toBe('blue');
|
||||||
|
|
||||||
|
comps[1].id = 'red';
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
// now second element should take updated value
|
||||||
|
expect(hostBindingEls[1].id).toBe('red');
|
||||||
|
});
|
||||||
|
|
||||||
it('should support dirs with host bindings on the same node as dirs without host bindings',
|
it('should support dirs with host bindings on the same node as dirs without host bindings',
|
||||||
() => {
|
() => {
|
||||||
const SomeDir = createDirective('someDir');
|
const SomeDir = createDirective('someDir');
|
||||||
|
@ -253,9 +323,11 @@ describe('host bindings', () => {
|
||||||
template: (rf: RenderFlags, ctx: InitHookComp) => {},
|
template: (rf: RenderFlags, ctx: InitHookComp) => {},
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
features: [NgOnChangesFeature],
|
features: [NgOnChangesFeature],
|
||||||
hostBindings: (rf: RenderFlags, ctx: InitHookComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: InitHookComp, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'title', bind(ctx.value));
|
elementProperty(elIndex, 'title', bind(ctx.value));
|
||||||
}
|
}
|
||||||
|
@ -420,9 +492,11 @@ describe('host bindings', () => {
|
||||||
factory: () => hostBindingComp = new HostBindingComp(),
|
factory: () => hostBindingComp = new HostBindingComp(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 8,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
||||||
// LView: [..., id, dir, title, ctx.id, pf1, ctx.title, ctx.otherTitle, pf2]
|
// LView: [..., id, dir, title, ctx.id, pf1, ctx.title, ctx.otherTitle, pf2]
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(8);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(pureFunction1(3, ff, ctx.id)));
|
elementProperty(elIndex, 'id', bind(pureFunction1(3, ff, ctx.id)));
|
||||||
elementProperty(elIndex, 'dir', bind(ctx.dir));
|
elementProperty(elIndex, 'dir', bind(ctx.dir));
|
||||||
|
@ -496,9 +570,11 @@ describe('host bindings', () => {
|
||||||
factory: () => hostBindingComp = new HostBindingComp(),
|
factory: () => hostBindingComp = new HostBindingComp(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 3,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
||||||
// LView: [..., id, ctx.id, pf1]
|
// LView: [..., id, ctx.id, pf1]
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(3);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(pureFunction1(1, ff, ctx.id)));
|
elementProperty(elIndex, 'id', bind(pureFunction1(1, ff, ctx.id)));
|
||||||
}
|
}
|
||||||
|
@ -525,9 +601,11 @@ describe('host bindings', () => {
|
||||||
type: HostBindingDir,
|
type: HostBindingDir,
|
||||||
selectors: [['', 'hostDir', '']],
|
selectors: [['', 'hostDir', '']],
|
||||||
factory: () => hostBindingDir = new HostBindingDir(),
|
factory: () => hostBindingDir = new HostBindingDir(),
|
||||||
hostVars: 3,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingDir, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingDir, elIndex: number) => {
|
||||||
// LView [..., title, ctx.title, pf1]
|
// LView: [..., title, ctx.title, pf1]
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(3);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'title', bind(pureFunction1(1, ff1, ctx.title)));
|
elementProperty(elIndex, 'title', bind(pureFunction1(1, ff1, ctx.title)));
|
||||||
}
|
}
|
||||||
|
@ -559,6 +637,69 @@ describe('host bindings', () => {
|
||||||
expect(hostElement.id).toBe('red,green');
|
expect(hostElement.id).toBe('red,green');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support directives with and without allocHostVars on the same component', () => {
|
||||||
|
let events: string[] = [];
|
||||||
|
|
||||||
|
const ff1 = (v: any) => [v, 'other title'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Directive({
|
||||||
|
* ...
|
||||||
|
* host: {
|
||||||
|
* '[title]': '[title, 'other title']'
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HostBindingDir {
|
||||||
|
title = 'my title';
|
||||||
|
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: HostBindingDir,
|
||||||
|
selectors: [['', 'hostDir', '']],
|
||||||
|
factory: () => new HostBindingDir(),
|
||||||
|
hostBindings: (rf: RenderFlags, ctx: HostBindingDir, elIndex: number) => {
|
||||||
|
// LViewData [..., title, ctx.title, pf1]
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(3);
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
elementProperty(elIndex, 'title', bind(pureFunction1(1, ff1, ctx.title)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class HostListenerDir {
|
||||||
|
/* @HostListener('click') */
|
||||||
|
onClick() { events.push('click!'); }
|
||||||
|
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: HostListenerDir,
|
||||||
|
selectors: [['', 'hostListenerDir', '']],
|
||||||
|
factory: function HostListenerDir_Factory() { return new HostListenerDir(); },
|
||||||
|
hostBindings: function HostListenerDir_HostBindings(
|
||||||
|
rf: RenderFlags, ctx: any, elIndex: number) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
listener('click', function() { return ctx.onClick(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// <button hostListenerDir hostDir>Click</button>
|
||||||
|
const fixture = new TemplateFixture(() => {
|
||||||
|
elementStart(0, 'button', ['hostListenerDir', '', 'hostDir', '']);
|
||||||
|
text(1, 'Click');
|
||||||
|
elementEnd();
|
||||||
|
}, () => {}, 2, 0, [HostListenerDir, HostBindingDir]);
|
||||||
|
|
||||||
|
const button = fixture.hostElement.querySelector('button') !;
|
||||||
|
button.click();
|
||||||
|
expect(events).toEqual(['click!']);
|
||||||
|
expect(button.title).toEqual('my title,other title');
|
||||||
|
});
|
||||||
|
|
||||||
it('should support ternary expressions in host bindings', () => {
|
it('should support ternary expressions in host bindings', () => {
|
||||||
let hostBindingComp !: HostBindingComp;
|
let hostBindingComp !: HostBindingComp;
|
||||||
|
|
||||||
|
@ -587,9 +728,11 @@ describe('host bindings', () => {
|
||||||
factory: () => hostBindingComp = new HostBindingComp(),
|
factory: () => hostBindingComp = new HostBindingComp(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 6,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingComp, elIndex: number) => {
|
||||||
// LView: [..., id, title, ctx.id, pf1, ctx.title, pf1]
|
// LView: [..., id, title, ctx.id, pf1, ctx.title, pf1]
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(6);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(
|
elementProperty(
|
||||||
elIndex, 'id', bind(ctx.condition ? pureFunction1(2, ff, ctx.id) : 'green'));
|
elIndex, 'id', bind(ctx.condition ? pureFunction1(2, ff, ctx.id) : 'green'));
|
||||||
|
@ -677,8 +820,10 @@ describe('host bindings', () => {
|
||||||
factory: () => new HostBindingWithContentChildren(),
|
factory: () => new HostBindingWithContentChildren(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingWithContentChildren, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingWithContentChildren, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(ctx.foos.length));
|
elementProperty(elIndex, 'id', bind(ctx.foos.length));
|
||||||
}
|
}
|
||||||
|
@ -734,8 +879,10 @@ describe('host bindings', () => {
|
||||||
factory: () => new HostBindingWithContentHooks(),
|
factory: () => new HostBindingWithContentHooks(),
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: HostBindingWithContentHooks, elIndex: number) => {
|
hostBindings: (rf: RenderFlags, ctx: HostBindingWithContentHooks, elIndex: number) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'id', bind(ctx.myValue));
|
elementProperty(elIndex, 'id', bind(ctx.myValue));
|
||||||
}
|
}
|
||||||
|
@ -755,5 +902,4 @@ describe('host bindings', () => {
|
||||||
const hostBindingEl = fixture.hostElement.querySelector('host-binding-comp') as HTMLElement;
|
const hostBindingEl = fixture.hostElement.querySelector('host-binding-comp') as HTMLElement;
|
||||||
expect(hostBindingEl.id).toEqual('after-content');
|
expect(hostBindingEl.id).toEqual('after-content');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||||
import {RendererStyleFlags2, RendererType2} from '../../src/render/api';
|
import {RendererStyleFlags2, RendererType2} from '../../src/render/api';
|
||||||
import {AttributeMarker, defineComponent, defineDirective, templateRefExtractor} from '../../src/render3/index';
|
import {AttributeMarker, defineComponent, defineDirective, templateRefExtractor} from '../../src/render3/index';
|
||||||
|
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, reference, text, textBinding, template, elementStylingMap, directiveInject} from '../../src/render3/instructions';
|
import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, projection, projectionDef, reference, text, textBinding, template, elementStylingMap, directiveInject} from '../../src/render3/instructions';
|
||||||
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
|
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3, RText, RComment, RNode, RendererStyleFlags3, ProceduralRenderer3} from '../../src/render3/interfaces/renderer';
|
import {RElement, Renderer3, RendererFactory3, domRendererFactory3, RText, RComment, RNode, RendererStyleFlags3, ProceduralRenderer3} from '../../src/render3/interfaces/renderer';
|
||||||
import {NO_CHANGE} from '../../src/render3/tokens';
|
import {NO_CHANGE} from '../../src/render3/tokens';
|
||||||
|
@ -446,8 +446,10 @@ describe('render3 integration test', () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
factory: () => cmptInstance = new TodoComponentHostBinding,
|
factory: () => cmptInstance = new TodoComponentHostBinding,
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void {
|
hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
// host bindings
|
// host bindings
|
||||||
elementProperty(elementIndex, 'title', bind(ctx.title));
|
elementProperty(elementIndex, 'title', bind(ctx.title));
|
||||||
|
@ -1379,9 +1381,11 @@ describe('render3 integration test', () => {
|
||||||
factory: function HostBindingDir_Factory() {
|
factory: function HostBindingDir_Factory() {
|
||||||
return hostBindingDir = new HostBindingDir();
|
return hostBindingDir = new HostBindingDir();
|
||||||
},
|
},
|
||||||
hostVars: 1,
|
|
||||||
hostBindings: function HostBindingDir_HostBindings(
|
hostBindings: function HostBindingDir_HostBindings(
|
||||||
rf: RenderFlags, ctx: any, elIndex: number) {
|
rf: RenderFlags, ctx: any, elIndex: number) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementAttribute(elIndex, 'aria-label', bind(ctx.label));
|
elementAttribute(elIndex, 'aria-label', bind(ctx.label));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, El
|
||||||
import {ViewEncapsulation} from '../../src/metadata';
|
import {ViewEncapsulation} from '../../src/metadata';
|
||||||
import {AttributeMarker, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load, query, queryRefresh} from '../../src/render3/index';
|
import {AttributeMarker, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load, query, queryRefresh} from '../../src/render3/index';
|
||||||
|
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
|
import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {RElement} from '../../src/render3/interfaces/renderer';
|
import {RElement} from '../../src/render3/interfaces/renderer';
|
||||||
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
|
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
|
||||||
|
@ -1836,9 +1836,11 @@ describe('ViewContainerRef', () => {
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
template: (rf: RenderFlags, cmp: HostBindingCmpt) => {},
|
template: (rf: RenderFlags, cmp: HostBindingCmpt) => {},
|
||||||
hostVars: 1,
|
|
||||||
attributes: ['id', 'attribute'],
|
attributes: ['id', 'attribute'],
|
||||||
hostBindings: function(rf: RenderFlags, ctx: HostBindingCmpt, elIndex: number) {
|
hostBindings: function(rf: RenderFlags, ctx: HostBindingCmpt, elIndex: number) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
allocHostVars(1);
|
||||||
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(elIndex, 'title', bind(ctx.title));
|
elementProperty(elIndex, 'title', bind(ctx.title));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue