feat(ivy): add support to template local refs in the compiler (#25576)

Fixes #23316

PR Close #25576
This commit is contained in:
Pawel Kozlowski
2018-08-20 14:23:17 +02:00
committed by Jason Aden
parent b05d4a5007
commit 11e2d9da1a
4 changed files with 83 additions and 24 deletions

View File

@ -118,6 +118,9 @@ export class Identifiers {
static directiveInject: o.ExternalReference = {name: 'ɵdirectiveInject', moduleName: CORE};
static templateRefExtractor:
o.ExternalReference = {name: 'ɵtemplateRefExtractor', moduleName: CORE};
static defineBase: o.ExternalReference = {name: 'ɵdefineBase', moduleName: CORE};
static BaseDef: o.ExternalReference = {

View File

@ -457,30 +457,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
o.TYPED_NULL_EXPR;
parameters.push(attrArg);
if (element.references && element.references.length > 0) {
const references = flatten(element.references.map(reference => {
const slot = this.allocateDataSlot();
// Generate the update temporary.
const variableName = this._bindingScope.freshReferenceName();
const retrievalLevel = this.level;
const lhs = o.variable(variableName);
this._bindingScope.set(
retrievalLevel, reference.name, lhs, DeclarationPriority.DEFAULT,
(scope: BindingScope, relativeLevel: number) => {
// e.g. x(2);
const nextContextStmt =
relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
// e.g. const $foo$ = r(1);
const refExpr = lhs.set(o.importExpr(R3.reference).callFn([o.literal(slot)]));
return nextContextStmt.concat(refExpr.toConstDecl());
});
return [reference.name, reference.value];
}));
parameters.push(this.constantPool.getConstLiteral(asLiteral(references), true));
} else {
parameters.push(o.TYPED_NULL_EXPR);
}
// local refs (ex.: <div #foo #bar="baz">)
parameters.push(this.prepareRefsParameter(element.references));
const wasInNamespace = this._namespace;
const currentNamespace = this.getNamespaceInstruction(namespaceKey);
@ -730,6 +708,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
if (attributeNames.length) {
parameters.push(this.constantPool.getConstLiteral(o.literalArr(attributeNames), true));
} else {
parameters.push(o.TYPED_NULL_EXPR);
}
// local refs (ex.: <ng-template #foo>)
if (template.references && template.references.length) {
parameters.push(this.prepareRefsParameter(template.references));
parameters.push(o.importExpr(R3.templateRefExtractor));
}
// e.g. p(1, 'forOf', ɵbind(ctx.items));
@ -858,6 +844,34 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
return value instanceof Interpolation || skipBindFn ? valExpr :
o.importExpr(R3.bind).callFn([valExpr]);
}
private prepareRefsParameter(references: t.Reference[]): o.Expression {
if (!references || references.length === 0) {
return o.TYPED_NULL_EXPR;
}
const refsParam = flatten(references.map(reference => {
const slot = this.allocateDataSlot();
// Generate the update temporary.
const variableName = this._bindingScope.freshReferenceName();
const retrievalLevel = this.level;
const lhs = o.variable(variableName);
this._bindingScope.set(
retrievalLevel, reference.name, lhs, DeclarationPriority.DEFAULT,
(scope: BindingScope, relativeLevel: number) => {
// e.g. x(2);
const nextContextStmt =
relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
// e.g. const $foo$ = r(1);
const refExpr = lhs.set(o.importExpr(R3.reference).callFn([o.literal(slot)]));
return nextContextStmt.concat(refExpr.toConstDecl());
});
return [reference.name, reference.value];
}));
return this.constantPool.getConstLiteral(asLiteral(refsParam), true);
}
}
class ValueConverter extends AstMemoryEfficientTransformer {