Skip to content

Commit 5379812

Browse files
committed
fix(compiler): Allow templates to access variables that are declared afterwards.
Fixes angular#8261
1 parent 955c8c6 commit 5379812

File tree

4 files changed

+26
-24
lines changed

4 files changed

+26
-24
lines changed

modules/angular2/src/compiler/view_compiler/view_binder.ts

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class ViewBinderVisitor implements TemplateAstVisitor {
101101
bindDirectiveDestroyLifecycleCallbacks(directiveAst.directive, directiveInstance,
102102
compileElement);
103103
});
104+
bindView(compileElement.embeddedView, ast.children);
104105
return null;
105106
}
106107

modules/angular2/src/compiler/view_compiler/view_builder.ts

+13-16
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ import {
5151
CompileTokenMetadata
5252
} from '../compile_metadata';
5353

54-
import {bindView} from './view_binder';
55-
5654
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
5755
const CLASS_ATTR = 'class';
5856
const STYLE_ATTR = 'style';
@@ -66,28 +64,28 @@ export class ViewCompileDependency {
6664
}
6765

6866
export function buildView(view: CompileView, template: TemplateAst[],
69-
targetDependencies: ViewCompileDependency[],
70-
targetStatements: o.Statement[]): number {
71-
var builderVisitor = new ViewBuilderVisitor(view, targetDependencies, targetStatements);
67+
targetDependencies: ViewCompileDependency[]): number {
68+
var builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
7269
templateVisitAll(builderVisitor, template, view.declarationElement.isNull() ?
7370
view.declarationElement :
7471
view.declarationElement.parent);
75-
// Need to separate binding from creation to be able to refer to
76-
// variables that have been declared after usage.
77-
bindView(view, template);
78-
view.afterNodes();
79-
80-
createViewTopLevelStmts(view, targetStatements);
81-
8272
return builderVisitor.nestedViewCount;
8373
}
8474

75+
export function finishView(view: CompileView, targetStatements: o.Statement[]) {
76+
view.afterNodes();
77+
createViewTopLevelStmts(view, targetStatements);
78+
view.nodes.forEach((node) => {
79+
if (node instanceof CompileElement && isPresent(node.embeddedView)) {
80+
finishView(node.embeddedView, targetStatements);
81+
}
82+
});
83+
}
8584

8685
class ViewBuilderVisitor implements TemplateAstVisitor {
8786
nestedViewCount: number = 0;
8887

89-
constructor(public view: CompileView, public targetDependencies: ViewCompileDependency[],
90-
public targetStatements: o.Statement[]) {}
88+
constructor(public view: CompileView, public targetDependencies: ViewCompileDependency[]) {}
9189

9290
private _isRootNode(parent: CompileElement): boolean { return parent.view !== this.view; }
9391

@@ -287,8 +285,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
287285
var embeddedView = new CompileView(
288286
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
289287
this.view.viewIndex + this.nestedViewCount, compileElement, templateVariableBindings);
290-
this.nestedViewCount +=
291-
buildView(embeddedView, ast.children, this.targetDependencies, this.targetStatements);
288+
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
292289

293290
compileElement.beforeChildren();
294291
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);

modules/angular2/src/compiler/view_compiler/view_compiler.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {Injectable} from 'angular2/src/core/di';
33
import * as o from '../output/output_ast';
44
import {CompileElement} from './compile_element';
55
import {CompileView} from './compile_view';
6-
import {buildView, ViewCompileDependency} from './view_builder';
6+
import {buildView, finishView, ViewCompileDependency} from './view_builder';
7+
import {bindView} from './view_binder';
78

89
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
910

@@ -25,7 +26,12 @@ export class ViewCompiler {
2526
var dependencies = [];
2627
var view = new CompileView(component, this._genConfig, pipes, styles, 0,
2728
CompileElement.createNull(), []);
28-
buildView(view, template, dependencies, statements);
29+
buildView(view, template, dependencies);
30+
// Need to separate binding from creation to be able to refer to
31+
// variables that have been declared after usage.
32+
bindView(view, template);
33+
finishView(view, statements);
34+
2935
return new ViewCompileResult(statements, view.viewFactory.name, dependencies);
3036
}
3137
}

modules/angular2/test/core/linker/integration_spec.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -588,18 +588,16 @@ function declareTests(isJit: boolean) {
588588
(tcb: TestComponentBuilder, async) => {
589589
tcb.overrideView(
590590
MyComp, new ViewMetadata({
591-
template: '<p>{{alice.ctxProp}}<child-cmp var-alice></child-cmp></p>',
592-
directives: [ChildComp]
591+
template:
592+
'<template [ngIf]="true">{{alice.ctxProp}}</template>|{{alice.ctxProp}}|<child-cmp var-alice></child-cmp>',
593+
directives: [ChildComp, NgIf]
593594
}))
594595

595596
.createAsync(MyComp)
596597
.then((fixture) => {
597598
fixture.detectChanges();
598599

599-
expect(fixture.debugElement.nativeElement)
600-
.toHaveText('hellohello'); // this first one is the
601-
// component, the second one is
602-
// the text binding
600+
expect(fixture.debugElement.nativeElement).toHaveText('hello|hello|hello');
603601
async.done();
604602
})}));
605603

0 commit comments

Comments
 (0)