feat(core): separate refs from vars.

Introduces `ref-` to give a name to an element or a directive (also works for `<template>` elements), and `let-` to introduce an input variable for a `<template>` element.

BREAKING CHANGE:
- `#...` now always means `ref-`.
- `<template #abc>` now defines a reference to the TemplateRef, instead of an input variable used inside of the template.
- `#...` inside of a *ngIf, … directives is deprecated.
  Use `let …` instead.
- `var-...` is deprecated. Replace with `let-...` for `<template>` elements and `ref-` for non `<template>` elements.

Closes #7158

Closes #8264
This commit is contained in:
Tobias Bosch
2016-04-25 19:52:24 -07:00
parent ff2ae7a2e1
commit d2efac18ed
69 changed files with 651 additions and 414 deletions
@@ -29,7 +29,7 @@ export function main() {
it('should clean up when the directive is destroyed',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div *ngFor="var item of items" [ngClass]="item"></div>';
var template = '<div *ngFor="let item of items" [ngClass]="item"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@@ -23,7 +23,7 @@ import {By} from 'angular2/platform/common_dom';
export function main() {
describe('ngFor', () => {
var TEMPLATE =
'<div><copy-me template="ngFor #item of items">{{item.toString()}};</copy-me></div>';
'<div><copy-me template="ngFor let item of items">{{item.toString()}};</copy-me></div>';
it('should reflect initial elements',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
@@ -100,7 +100,7 @@ export function main() {
it('should iterate over an array of objects',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<ul><li template="ngFor #item of items">{{item["name"]}};</li></ul>';
var template = '<ul><li template="ngFor let item of items">{{item["name"]}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -130,7 +130,7 @@ export function main() {
it('should gracefully handle nulls',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<ul><li template="ngFor #item of null">{{item}};</li></ul>';
var template = '<ul><li template="ngFor let item of null">{{item}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@@ -207,8 +207,8 @@ export function main() {
it('should repeat over nested arrays',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<div template="ngFor #item of items">' +
'<div template="ngFor #subitem of item">' +
'<div template="ngFor let item of items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
'</div>|' +
'</div>' +
@@ -233,8 +233,8 @@ export function main() {
it('should repeat over nested arrays with no intermediate element',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div><template ngFor #item [ngForOf]="items">' +
'<div template="ngFor #subitem of item">' +
var template = '<div><template ngFor let-item [ngForOf]="items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
'</div></template></div>';
@@ -255,7 +255,7 @@ export function main() {
it('should repeat over nested ngIf that are the last node in the ngFor temlate',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" #i="index"><div>{{i}}|</div>` +
`<div><template ngFor let-item [ngForOf]="items" let-i="index"><div>{{i}}|</div>` +
`<div *ngIf="i % 2 == 0">even|</div></template></div>`;
tcb.overrideTemplate(TestComponent, template)
@@ -282,7 +282,7 @@ export function main() {
it('should display indices correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: var item of items; var i=index">{{i.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let i=index">{{i.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -301,7 +301,7 @@ export function main() {
it('should display first item correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: var item of items; var isFirst=first">{{isFirst.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isFirst=first">{{isFirst.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -320,7 +320,7 @@ export function main() {
it('should display last item correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: var item of items; var isLast=last">{{isLast.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isLast=last">{{isLast.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -339,7 +339,7 @@ export function main() {
it('should display even items correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: var item of items; var isEven=even">{{isEven.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isEven=even">{{isEven.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -358,7 +358,7 @@ export function main() {
it('should display odd items correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: var item of items; var isOdd=odd">{{isOdd.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isOdd=odd">{{isOdd.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@@ -381,7 +381,7 @@ export function main() {
'<ul><template ngFor [ngForOf]="items" [ngForTemplate]="contentTpl"></template></ul>')
.overrideTemplate(
ComponentUsingTestComponent,
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.children[0];
@@ -395,8 +395,8 @@ export function main() {
it('should use a default template if a custom one is null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(TestComponent, `<ul><template ngFor #item [ngForOf]="items"
[ngForTemplate]="contentTpl" #i="index">{{i}}: {{item}};</template></ul>`)
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
[ngForTemplate]="contentTpl" let-i="index">{{i}}: {{item}};</template></ul>`)
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
@@ -411,11 +411,11 @@ export function main() {
it('should use a custom template when both default and a custom one are present',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(TestComponent, `<ul><template ngFor #item [ngForOf]="items"
[ngForTemplate]="contentTpl" #i="index">{{i}}=> {{item}};</template></ul>`)
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
[ngForTemplate]="contentTpl" let-i="index">{{i}}=> {{item}};</template></ul>`)
.overrideTemplate(
ComponentUsingTestComponent,
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.children[0];
@@ -431,7 +431,7 @@ export function main() {
it('should not replace tracked items',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById" #i="index">
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById" let-i="index">
<p>{{items[i]}}</p>
</template>`;
tcb.overrideTemplate(TestComponent, template)
@@ -453,7 +453,7 @@ export function main() {
it('should update implicit local variable on view',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@@ -469,7 +469,7 @@ export function main() {
it('should move items around and keep them updated ',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@@ -488,7 +488,7 @@ export function main() {
it('should handle added and removed items properly when tracking by index',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor #item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@@ -448,7 +448,7 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
var t = `<select>
<option *ngFor="#city of list" [value]="city['id']">
<option *ngFor="let city of list" [value]="city['id']">
{{ city['name'] }}
</option>
</select>`;
@@ -503,7 +503,7 @@ export function main() {
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
var t = `<div [ngFormModel]="form">
<select ngControl="city">
<option *ngFor="#c of data" [value]="c"></option>
<option *ngFor="let c of data" [value]="c"></option>
</select>
</div>`;
@@ -528,7 +528,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list" [ngValue]="c">{{c['name']}}</option>
<option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option>
</select>
</div>`;
@@ -560,7 +560,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list" [ngValue]="c">{{c['name']}}</option>
<option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option>
</select>
</div>`;
@@ -588,7 +588,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list" [ngValue]="c">{{c}}</option>
<option *ngFor="let c of list" [ngValue]="c">{{c}}</option>
</select>
</div>`;
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((fixture) => {
@@ -614,7 +614,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list; trackBy:customTrackBy" [ngValue]="c">{{c}}</option>
<option *ngFor="let c of list; trackBy:customTrackBy" [ngValue]="c">{{c}}</option>
</select>
</div>`;
@@ -644,7 +644,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list" [ngValue]="c">{{c}}</option>
<option *ngFor="let c of list" [ngValue]="c">{{c}}</option>
</select>
</div>`;
@@ -673,7 +673,7 @@ export function main() {
(tcb: TestComponentBuilder, async) => {
var t = `<div>
<select [(ngModel)]="selectedCity">
<option *ngFor="#c of list" [ngValue]="c">{{c['name']}}</option>
<option *ngFor="let c of list" [ngValue]="c">{{c['name']}}</option>
</select>
</div>`;
@@ -17,7 +17,7 @@ export function main() {
}
function parseTemplateBindings(text, location = null): any {
return createParser().parseTemplateBindings(text, location);
return createParser().parseTemplateBindings(text, location).templateBindings;
}
function parseInterpolation(text, location = null): any {
@@ -293,7 +293,7 @@ export function main() {
function keyValues(templateBindings: any[]) {
return templateBindings.map(binding => {
if (binding.keyIsVar) {
return '#' + binding.key + (isBlank(binding.name) ? '=null' : '=' + binding.name);
return 'let ' + binding.key + (isBlank(binding.name) ? '=null' : '=' + binding.name);
} else {
return binding.key + (isBlank(binding.expression) ? '' : `=${binding.expression}`)
}
@@ -339,8 +339,8 @@ export function main() {
});
it('should detect names as value', () => {
var bindings = parseTemplateBindings("a:#b");
expect(keyValues(bindings)).toEqual(['a', '#b=\$implicit']);
var bindings = parseTemplateBindings("a:let b");
expect(keyValues(bindings)).toEqual(['a', 'let b=\$implicit']);
});
it('should allow space and colon as separators', () => {
@@ -370,31 +370,46 @@ export function main() {
expect(bindings[0].expression.location).toEqual('location');
});
it('should support var/# notation', () => {
var bindings = parseTemplateBindings("var i");
expect(keyValues(bindings)).toEqual(['#i=\$implicit']);
it('should support var notation with a deprecation warning', () => {
var bindings = createParser().parseTemplateBindings("var i", null);
expect(keyValues(bindings.templateBindings)).toEqual(['let i=\$implicit']);
expect(bindings.warnings)
.toEqual(['"var" inside of expressions is deprecated. Use "let" instead!']);
});
bindings = parseTemplateBindings("#i");
expect(keyValues(bindings)).toEqual(['#i=\$implicit']);
it('should support # notation with a deprecation warning', () => {
var bindings = createParser().parseTemplateBindings("#i", null);
expect(keyValues(bindings.templateBindings)).toEqual(['let i=\$implicit']);
expect(bindings.warnings)
.toEqual(['"#" inside of expressions is deprecated. Use "let" instead!']);
});
bindings = parseTemplateBindings("var a; var b");
expect(keyValues(bindings)).toEqual(['#a=\$implicit', '#b=\$implicit']);
it('should support let notation', () => {
var bindings = parseTemplateBindings("let i");
expect(keyValues(bindings)).toEqual(['let i=\$implicit']);
bindings = parseTemplateBindings("#a; #b;");
expect(keyValues(bindings)).toEqual(['#a=\$implicit', '#b=\$implicit']);
bindings = parseTemplateBindings("let i");
expect(keyValues(bindings)).toEqual(['let i=\$implicit']);
bindings = parseTemplateBindings("var i-a = k-a");
expect(keyValues(bindings)).toEqual(['#i-a=k-a']);
bindings = parseTemplateBindings("let a; let b");
expect(keyValues(bindings)).toEqual(['let a=\$implicit', 'let b=\$implicit']);
bindings = parseTemplateBindings("keyword var item; var i = k");
expect(keyValues(bindings)).toEqual(['keyword', '#item=\$implicit', '#i=k']);
bindings = parseTemplateBindings("let a; let b;");
expect(keyValues(bindings)).toEqual(['let a=\$implicit', 'let b=\$implicit']);
bindings = parseTemplateBindings("keyword: #item; #i = k");
expect(keyValues(bindings)).toEqual(['keyword', '#item=\$implicit', '#i=k']);
bindings = parseTemplateBindings("let i-a = k-a");
expect(keyValues(bindings)).toEqual(['let i-a=k-a']);
bindings = parseTemplateBindings("directive: var item in expr; var a = b", 'location');
bindings = parseTemplateBindings("keyword let item; let i = k");
expect(keyValues(bindings)).toEqual(['keyword', 'let item=\$implicit', 'let i=k']);
bindings = parseTemplateBindings("keyword: let item; let i = k");
expect(keyValues(bindings)).toEqual(['keyword', 'let item=\$implicit', 'let i=k']);
bindings = parseTemplateBindings("directive: let item in expr; let a = b", 'location');
expect(keyValues(bindings))
.toEqual(['directive', '#item=\$implicit', 'directiveIn=expr in location', '#a=b']);
.toEqual(
['directive', 'let item=\$implicit', 'directiveIn=expr in location', 'let a=b']);
});
it('should parse pipes', () => {
@@ -1,5 +1,6 @@
import {print, IS_DART} from 'angular2/src/facade/lang';
import {OutputEmitter} from 'angular2/src/compiler/output/abstract_emitter';
import {Console} from 'angular2/src/core/console';
import {
OfflineCompiler,
@@ -48,8 +49,8 @@ function _createOfflineCompiler(xhr: MockXHR, emitter: OutputEmitter): OfflineCo
var htmlParser = new HtmlParser();
var normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser);
return new OfflineCompiler(
normalizer,
new TemplateParser(new Parser(new Lexer()), new MockSchemaRegistry({}, {}), htmlParser, []),
normalizer, new TemplateParser(new Parser(new Lexer()), new MockSchemaRegistry({}, {}),
htmlParser, new Console(), []),
new StyleCompiler(urlResolver), new ViewCompiler(new CompilerConfig(true, true, true)),
emitter);
}
@@ -11,6 +11,7 @@ import {
beforeEachProviders
} from 'angular2/testing_internal';
import {provide} from 'angular2/src/core/di';
import {Console} from 'angular2/src/core/console';
import {TEST_PROVIDERS} from './test_bindings';
import {isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
@@ -36,6 +37,7 @@ import {
NgContentAst,
EmbeddedTemplateAst,
ElementAst,
ReferenceAst,
VariableAst,
BoundEventAst,
BoundElementPropertyAst,
@@ -47,6 +49,7 @@ import {
DirectiveAst,
ProviderAstType
} from 'angular2/src/compiler/template_ast';
import {identifierToken, Identifiers} from 'angular2/src/compiler/identifiers';
import {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry';
import {MockSchemaRegistry} from './schema_registry_mock';
@@ -66,8 +69,13 @@ var MOCK_SCHEMA_REGISTRY = [
export function main() {
var ngIf;
var parse;
var console: ArrayConsole;
function commonBeforeEach() {
beforeEachProviders(() => {
console = new ArrayConsole();
return [provide(Console, {useValue: console})];
});
beforeEach(inject([TemplateParser], (parser) => {
var component = CompileDirectiveMetadata.create({
selector: 'root',
@@ -310,7 +318,7 @@ export function main() {
});
describe('directives', () => {
it('should locate directives components first and ordered by the directives array in the View',
it('should order directives by the directives array in the View and match them only once',
() => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
@@ -324,19 +332,14 @@ export function main() {
selector: '[c]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirC'})
});
var comp = CompileDirectiveMetadata.create({
selector: 'div',
isComponent: true,
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'ZComp'}),
template: new CompileTemplateMetadata({ngContentSelectors: []})
});
expect(humanizeTplAst(parse('<div a c b>', [dirA, dirB, dirC, comp])))
expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC])))
.toEqual([
[ElementAst, 'div'],
[AttrAst, 'a', ''],
[AttrAst, 'c', ''],
[AttrAst, 'b', ''],
[DirectiveAst, comp],
[AttrAst, 'a', ''],
[AttrAst, 'b', ''],
[DirectiveAst, dirA],
[DirectiveAst, dirB],
[DirectiveAst, dirC]
@@ -747,29 +750,41 @@ export function main() {
});
});
describe('variables', () => {
describe('references', () => {
it('should parse variables via #... and not report them as attributes', () => {
it('should parse references via #... and not report them as attributes', () => {
expect(humanizeTplAst(parse('<div #a>', [])))
.toEqual([[ElementAst, 'div'], [VariableAst, 'a', '']]);
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
});
it('should parse variables via var-... and not report them as attributes', () => {
it('should parse references via ref-... and not report them as attributes', () => {
expect(humanizeTplAst(parse('<div ref-a>', [])))
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
});
it('should parse references via var-... and report them as deprecated', () => {
expect(humanizeTplAst(parse('<div var-a>', [])))
.toEqual([[ElementAst, 'div'], [VariableAst, 'a', '']]);
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
expect(console.warnings)
.toEqual([
[
'Template parse warnings:',
'"var-" on non <template> elements is deprecated. Use "ref-" instead! ("<div [ERROR ->]var-a>"): TestComp@0:5'
].join('\n')
]);
});
it('should parse camel case variables', () => {
expect(humanizeTplAst(parse('<div var-someA>', [])))
.toEqual([[ElementAst, 'div'], [VariableAst, 'someA', '']]);
it('should parse camel case references', () => {
expect(humanizeTplAst(parse('<div ref-someA>', [])))
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'someA', null]]);
});
it('should assign variables with empty value to the element', () => {
it('should assign references with empty value to the element', () => {
expect(humanizeTplAst(parse('<div #a></div>', [])))
.toEqual([[ElementAst, 'div'], [VariableAst, 'a', '']]);
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
});
it('should assign variables to directives via exportAs', () => {
it('should assign references to directives via exportAs', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}),
@@ -779,28 +794,27 @@ export function main() {
.toEqual([
[ElementAst, 'div'],
[AttrAst, 'a', ''],
[ReferenceAst, 'a', identifierToken(dirA.type)],
[DirectiveAst, dirA],
[VariableAst, 'a', 'dirA']
]);
});
it('should report variables with values that dont match a directive as errors', () => {
it('should report references with values that dont match a directive as errors', () => {
expect(() => parse('<div #a="dirA"></div>', [])).toThrowError(`Template parse errors:
There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"></div>"): TestComp@0:5`);
});
it('should report invalid variable names', () => {
it('should report invalid reference names', () => {
expect(() => parse('<div #a-b></div>', [])).toThrowError(`Template parse errors:
"-" is not allowed in variable names ("<div [ERROR ->]#a-b></div>"): TestComp@0:5`);
"-" is not allowed in reference names ("<div [ERROR ->]#a-b></div>"): TestComp@0:5`);
});
it('should allow variables with values that dont match a directive on embedded template elements',
() => {
expect(humanizeTplAst(parse('<template #a="b"></template>', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
});
it('should report variables as errors', () => {
expect(() => parse('<div let-a></div>', [])).toThrowError(`Template parse errors:
"let-" is only supported on template elements. ("<div [ERROR ->]let-a></div>"): TestComp@0:5`);
});
it('should assign variables with empty value to components', () => {
it('should assign references with empty value to components', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
isComponent: true,
@@ -812,12 +826,19 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
.toEqual([
[ElementAst, 'div'],
[AttrAst, 'a', ''],
[VariableAst, 'a', ''],
[ReferenceAst, 'a', identifierToken(dirA.type)],
[DirectiveAst, dirA],
[VariableAst, 'a', '']
]);
});
it('should not locate directives in references', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
});
expect(humanizeTplAst(parse('<div ref-a>', [dirA])))
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
});
});
describe('explicit templates', () => {
@@ -836,6 +857,49 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
[EmbeddedTemplateAst],
]);
});
it('should support references via #...', () => {
expect(humanizeTplAst(parse('<template #a>', [])))
.toEqual([
[EmbeddedTemplateAst],
[ReferenceAst, 'a', identifierToken(Identifiers.TemplateRef)]
]);
});
it('should support references via ref-...', () => {
expect(humanizeTplAst(parse('<template ref-a>', [])))
.toEqual([
[EmbeddedTemplateAst],
[ReferenceAst, 'a', identifierToken(Identifiers.TemplateRef)]
]);
});
it('should parse variables via let-...', () => {
expect(humanizeTplAst(parse('<template let-a="b">', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
});
it('should parse variables via var-... and report them as deprecated', () => {
expect(humanizeTplAst(parse('<template var-a="b">', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
expect(console.warnings)
.toEqual([
[
'Template parse warnings:',
'"var-" on <template> elements is deprecated. Use "let-" instead! ("<template [ERROR ->]var-a="b">"): TestComp@0:10'
].join('\n')
]);
});
it('should not locate directives in variables', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
});
expect(humanizeTplAst(parse('<template let-a="b"></template>', [dirA])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
});
});
describe('inline templates', () => {
@@ -854,13 +918,32 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
]);
});
it('should parse variables via #...', () => {
expect(humanizeTplAst(parse('<div template="ngIf #a=b">', [])))
it('should parse variables via #... and report them as deprecated', () => {
expect(humanizeTplAst(parse('<div *ngIf="#a=b">', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
expect(console.warnings)
.toEqual([
[
'Template parse warnings:',
'"#" inside of expressions is deprecated. Use "let" instead! ("<div [ERROR ->]*ngIf="#a=b">"): TestComp@0:5'
].join('\n')
]);
});
it('should parse variables via var ...', () => {
expect(humanizeTplAst(parse('<div template="ngIf var a=b">', [])))
it('should parse variables via var ... and report them as deprecated', () => {
expect(humanizeTplAst(parse('<div *ngIf="var a=b">', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
expect(console.warnings)
.toEqual([
[
'Template parse warnings:',
'"var" inside of expressions is deprecated. Use "let" instead! ("<div [ERROR ->]*ngIf="var a=b">"): TestComp@0:5'
].join('\n')
]);
});
it('should parse variables via let ...', () => {
expect(humanizeTplAst(parse('<div *ngIf="let a=b">', [])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
});
@@ -886,24 +969,22 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
]);
});
it('should locate directives in variable bindings', () => {
it('should not locate directives in variables', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a=b]',
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
});
var dirB = CompileDirectiveMetadata.create({
selector: '[b]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirB'})
expect(humanizeTplAst(parse('<div template="let a=b">', [dirA])))
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
});
it('should not locate directives in references', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
});
expect(humanizeTplAst(parse('<div template="#a=b" b>', [dirA, dirB])))
.toEqual([
[EmbeddedTemplateAst],
[VariableAst, 'a', 'b'],
[DirectiveAst, dirA],
[ElementAst, 'div'],
[AttrAst, 'b', ''],
[DirectiveAst, dirB]
]);
expect(humanizeTplAst(parse('<div ref-a>', [dirA])))
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
});
});
@@ -1248,22 +1329,20 @@ Property binding a not used by any directive on an embedded template ("[ERROR ->
});
it('should support references', () => {
expect(humanizeTplAstSourceSpans(parse('<div #a></div>', [])))
.toEqual([[ElementAst, 'div', '<div #a>'], [ReferenceAst, 'a', null, '#a']]);
});
it('should support variables', () => {
var dirA = CompileDirectiveMetadata.create({
selector: '[a]',
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}),
exportAs: 'dirA'
});
expect(humanizeTplAstSourceSpans(parse('<div a #a="dirA"></div>', [dirA])))
expect(humanizeTplAstSourceSpans(parse('<template let-a="b"></template>', [])))
.toEqual([
[ElementAst, 'div', '<div a #a="dirA">'],
[AttrAst, 'a', '', 'a'],
[DirectiveAst, dirA, '<div a #a="dirA">'],
[VariableAst, 'a', 'dirA', '#a="dirA"']
[EmbeddedTemplateAst, '<template let-a="b">'],
[VariableAst, 'a', 'b', 'let-a="b"']
]);
});
it('should support event', () => {
it('should support events', () => {
expect(humanizeTplAstSourceSpans(parse('<div (window:event)="v">', [])))
.toEqual([
[ElementAst, 'div', '<div (window:event)="v">'],
@@ -1311,8 +1390,8 @@ Property binding a not used by any directive on an embedded template ("[ERROR ->
.toEqual([
[ElementAst, 'div', '<div a>'],
[AttrAst, 'a', '', 'a'],
[DirectiveAst, comp, '<div a>'],
[DirectiveAst, dirA, '<div a>'],
[DirectiveAst, comp, '<div a>']
]);
});
@@ -1399,7 +1478,8 @@ class TemplateHumanizer implements TemplateAstVisitor {
this.result.push(this._appendContext(ast, res));
templateVisitAll(this, ast.attrs);
templateVisitAll(this, ast.outputs);
templateVisitAll(this, ast.vars);
templateVisitAll(this, ast.references);
templateVisitAll(this, ast.variables);
templateVisitAll(this, ast.directives);
templateVisitAll(this, ast.children);
return null;
@@ -1410,11 +1490,16 @@ class TemplateHumanizer implements TemplateAstVisitor {
templateVisitAll(this, ast.attrs);
templateVisitAll(this, ast.inputs);
templateVisitAll(this, ast.outputs);
templateVisitAll(this, ast.exportAsVars);
templateVisitAll(this, ast.references);
templateVisitAll(this, ast.directives);
templateVisitAll(this, ast.children);
return null;
}
visitReference(ast: ReferenceAst, context: any): any {
var res = [ReferenceAst, ast.name, ast.value];
this.result.push(this._appendContext(ast, res));
return null;
}
visitVariable(ast: VariableAst, context: any): any {
var res = [VariableAst, ast.name, ast.value];
this.result.push(this._appendContext(ast, res));
@@ -1457,7 +1542,6 @@ class TemplateHumanizer implements TemplateAstVisitor {
templateVisitAll(this, ast.inputs);
templateVisitAll(this, ast.hostProperties);
templateVisitAll(this, ast.hostEvents);
templateVisitAll(this, ast.exportAsVars);
return null;
}
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
@@ -1499,6 +1583,7 @@ class TemplateContentProjectionHumanizer implements TemplateAstVisitor {
templateVisitAll(this, ast.children);
return null;
}
visitReference(ast: ReferenceAst, context: any): any { return null; }
visitVariable(ast: VariableAst, context: any): any { return null; }
visitEvent(ast: BoundEventAst, context: any): any { return null; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
@@ -1523,6 +1608,7 @@ class FooAstTransformer implements TemplateAstVisitor {
return new ElementAst('foo', [], [], [], [], [], [], false, [], ast.ngContentIndex,
ast.sourceSpan);
}
visitReference(ast: ReferenceAst, context: any): any { throw 'not implemented'; }
visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; }
visitEvent(ast: BoundEventAst, context: any): any { throw 'not implemented'; }
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { throw 'not implemented'; }
@@ -1542,3 +1628,10 @@ class BarAstTransformer extends FooAstTransformer {
ast.sourceSpan);
}
}
class ArrayConsole implements Console {
logs: string[] = [];
warnings: string[] = [];
log(msg: string) { this.logs.push(msg); }
warn(msg: string) { this.warnings.push(msg); }
}
@@ -179,4 +179,5 @@ class _MockComponentRef extends ComponentRef_ {
class _MockConsole implements Console {
log(message) {}
warn(message) {}
}
@@ -132,9 +132,9 @@ class ConditionalParentComp {
@Component({
selector: 'using-for',
viewProviders: [Logger],
template: `<span *ngFor="#thing of stuff" [innerHtml]="thing"></span>
template: `<span *ngFor="let thing of stuff" [innerHtml]="thing"></span>
<ul message="list">
<li *ngFor="#item of stuff" [innerHtml]="item"></li>
<li *ngFor="let item of stuff" [innerHtml]="item"></li>
</ul>`,
directives: [NgFor, MessageDir],
})
@@ -50,7 +50,7 @@ class App {
@Component({
selector: 'lock',
directives: [NgFor],
template: `{{frame.name}}(<span *ngFor="var lock of locks">{{lock.name}}</span>)`,
template: `{{frame.name}}(<span *ngFor="let lock of locks">{{lock.name}}</span>)`,
})
class Door {
locks: QueryList<Lock>;
@@ -438,7 +438,7 @@ export function main() {
it('should read locals', fakeAsync(() => {
var ctx =
createCompFixture('<template testLocals var-local="someLocal">{{local}}</template>');
createCompFixture('<template testLocals let-local="someLocal">{{local}}</template>');
ctx.detectChanges(false);
expect(renderLog.log).toEqual(['{{someLocalValue}}']);
@@ -581,7 +581,7 @@ export function main() {
it('should throw when trying to assign to a local', fakeAsync(() => {
expect(() => {_bindSimpleProp('(event)="$event=1"')})
.toThrowError(new RegExp("Cannot reassign a variable binding"));
.toThrowError(new RegExp("Cannot assign to a reference or variable!"));
}));
it('should support short-circuiting', fakeAsync(() => {
@@ -609,7 +609,7 @@ export function main() {
it('should read directive properties', fakeAsync(() => {
var ctx =
createCompFixture(
'<div testDirective [a]="42" var-dir="testDirective" [someProp]="dir.a"></div>')
'<div testDirective [a]="42" ref-dir="testDirective" [someProp]="dir.a"></div>')
ctx.detectChanges(false);
expect(renderLog.loggedValues).toEqual([42]);
}));
@@ -259,7 +259,7 @@ class OnChangeComponent implements OnChanges {
])
@View(
template:
'<span *ngFor="#item of list">{{item}}</span><directive-logging-checks></directive-logging-checks>',
'<span *ngFor="let item of list">{{item}}</span><directive-logging-checks></directive-logging-checks>',
directives: const [NgFor, DirectiveLoggingChecks])
class ComponentWithObservableList {
Iterable list;
@@ -89,7 +89,7 @@ import {EmbeddedViewRef} from 'angular2/src/core/linker/view_ref';
import {ComponentResolver} from 'angular2/src/core/linker/component_resolver';
import {ElementRef} from 'angular2/src/core/linker/element_ref';
import {TemplateRef} from 'angular2/src/core/linker/template_ref';
import {TemplateRef_, TemplateRef} from 'angular2/src/core/linker/template_ref';
import {Renderer} from 'angular2/src/core/render';
@@ -473,7 +473,7 @@ function declareTests(isJit: boolean) {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template>',
'<template some-viewport let-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template>',
directives: [SomeViewport]
}))
@@ -509,7 +509,7 @@ function declareTests(isJit: boolean) {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me>',
'<copy-me template="some-viewport: let greeting=some-tmpl">{{greeting}}</copy-me>',
directives: [SomeViewport]
}))
@@ -531,7 +531,7 @@ function declareTests(isJit: boolean) {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<some-directive><toolbar><template toolbarpart var-toolbarProp="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-host></cmp-with-host></template></toolbar></some-directive>',
'<some-directive><toolbar><template toolbarpart let-toolbarProp="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-host></cmp-with-host></template></toolbar></some-directive>',
directives: [SomeDirective, CompWithHost, ToolbarComponent, ToolbarPart]
}))
.createAsync(MyComp)
@@ -547,12 +547,12 @@ function declareTests(isJit: boolean) {
});
}));
describe("variable bindings", () => {
it('should assign a component to a var-',
describe("reference bindings", () => {
it('should assign a component to a ref-',
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<p><child-cmp var-alice></child-cmp></p>',
template: '<p><child-cmp ref-alice></child-cmp></p>',
directives: [ChildComp]
}))
@@ -564,7 +564,7 @@ function declareTests(isJit: boolean) {
async.done();
})}));
it('should assign a directive to a var-',
it('should assign a directive to a ref-',
inject(
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
@@ -588,7 +588,7 @@ function declareTests(isJit: boolean) {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<template [ngIf]="true">{{alice.ctxProp}}</template>|{{alice.ctxProp}}|<child-cmp var-alice></child-cmp>',
'<template [ngIf]="true">{{alice.ctxProp}}</template>|{{alice.ctxProp}}|<child-cmp ref-alice></child-cmp>',
directives: [ChildComp, NgIf]
}))
@@ -600,14 +600,14 @@ function declareTests(isJit: boolean) {
async.done();
})}));
it('should assign two component instances each with a var-',
it('should assign two component instances each with a ref-',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<p><child-cmp var-alice></child-cmp><child-cmp var-bob></child-cmp></p>',
'<p><child-cmp ref-alice></child-cmp><child-cmp ref-bob></child-cmp></p>',
directives: [ChildComp]
}))
@@ -622,7 +622,7 @@ function declareTests(isJit: boolean) {
async.done();
})}));
it('should assign the component instance to a var- with shorthand syntax',
it('should assign the component instance to a ref- with shorthand syntax',
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder,
async) => {tcb.overrideView(MyComp, new ViewMetadata({
@@ -643,7 +643,7 @@ function declareTests(isJit: boolean) {
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<div><div var-alice><i>Hello</i></div></div>'
template: '<div><div ref-alice><i>Hello</i></div></div>'
}))
.createAsync(MyComp)
@@ -657,11 +657,26 @@ function declareTests(isJit: boolean) {
async.done();
})}));
it('should assign the TemplateRef to a user-defined variable',
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata(
{template: '<template ref-alice></template>'}))
.createAsync(MyComp)
.then((fixture) => {
var value = fixture.debugElement.childNodes[0].getLocal('alice');
expect(value).toBeAnInstanceOf(TemplateRef_);
async.done();
})}));
it('should preserve case',
inject(
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({
template: '<p><child-cmp var-superAlice></child-cmp></p>',
template: '<p><child-cmp ref-superAlice></child-cmp></p>',
directives: [ChildComp]
}))
@@ -673,14 +688,16 @@ function declareTests(isJit: boolean) {
async.done();
});
}));
});
describe('variables', () => {
it('should allow to use variables in a for loop',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder,
async) => {
tcb.overrideView(
MyComp, new ViewMetadata({
template:
'<template ngFor [ngForOf]="[1]" var-i><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</template>',
'<template ngFor [ngForOf]="[1]" let-i><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</template>',
directives: [ChildCompNoTemplate, NgFor]
}))
@@ -2281,7 +2298,7 @@ class ToolbarViewContainer {
@Component({
selector: 'toolbar',
template: 'TOOLBAR(<div *ngFor="var part of query" [toolbarVc]="part"></div>)',
template: 'TOOLBAR(<div *ngFor="let part of query" [toolbarVc]="part"></div>)',
directives: [ToolbarViewContainer, NgFor]
})
@Injectable()
@@ -2489,7 +2506,7 @@ class DirectiveThrowingAnError {
@Component({
selector: 'component-with-template',
directives: [NgFor],
template: `No View Decorator: <div *ngFor="#item of items">{{item}}</div>`
template: `No View Decorator: <div *ngFor="let item of items">{{item}}</div>`
})
class ComponentWithTemplate {
items = [1, 2, 3];
@@ -246,7 +246,7 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div text="1"></div>' +
'<needs-query text="2"><div *ngFor="var i of list" [text]="i"></div></needs-query>' +
'<needs-query text="2"><div *ngFor="let i of list" [text]="i"></div></needs-query>' +
'<div text="4"></div>';
tcb.overrideTemplate(MyComp, template)
@@ -268,7 +268,7 @@ export function main() {
describe('query for TemplateRef', () => {
it('should find TemplateRefs in the light and shadow dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-tpl><template var-x="light"></template></needs-tpl>';
var template = '<needs-tpl><template let-x="light"></template></needs-tpl>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
@@ -284,6 +284,23 @@ export function main() {
});
}));
it('should find named TemplateRefs',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<needs-named-tpl><template let-x="light" #tpl></template></needs-named-tpl>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var needsTpl: NeedsNamedTpl = view.debugElement.children[0].inject(NeedsNamedTpl);
expect(needsTpl.vc.createEmbeddedView(needsTpl.contentTpl).hasLocal('light'))
.toBe(true);
expect(needsTpl.vc.createEmbeddedView(needsTpl.viewTpl).hasLocal('shadow'))
.toBe(true);
async.done();
});
}));
});
describe('read a different token', () => {
@@ -462,9 +479,10 @@ export function main() {
describe("querying by var binding", () => {
it('should contain all the child directives in the light dom with the given var binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-binding #q>' +
'<div *ngFor="#item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-var-binding>';
var template =
'<needs-query-by-ref-binding #q>' +
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-ref-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
@@ -484,10 +502,10 @@ export function main() {
it('should support querying by multiple var bindings',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-bindings #q>' +
var template = '<needs-query-by-ref-bindings #q>' +
'<div text="one" #textLabel1="textDir"></div>' +
'<div text="two" #textLabel2="textDir"></div>' +
'</needs-query-by-var-bindings>';
'</needs-query-by-ref-bindings>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
@@ -504,9 +522,10 @@ export function main() {
it('should support dynamically inserted directives',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-binding #q>' +
'<div *ngFor="#item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-var-binding>';
var template =
'<needs-query-by-ref-binding #q>' +
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
'</needs-query-by-ref-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
@@ -529,11 +548,11 @@ export function main() {
it('should contain all the elements in the light dom with the given var binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-query-by-var-binding #q>' +
'<div template="ngFor: #item of list">' +
var template = '<needs-query-by-ref-binding #q>' +
'<div template="ngFor: let item of list">' +
'<div #textLabel>{{item}}</div>' +
'</div>' +
'</needs-query-by-var-binding>';
'</needs-query-by-ref-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
@@ -570,7 +589,7 @@ export function main() {
it('should support querying the view by using a view query',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-view-query-by-var-binding #q></needs-view-query-by-var-binding>';
var template = '<needs-view-query-by-ref-binding #q></needs-view-query-by-ref-binding>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
@@ -859,7 +878,7 @@ class InertDirective {
@Component({
selector: 'needs-query',
directives: [NgFor, TextDirective],
template: '<div text="ignoreme"></div><b *ngFor="var dir of query">{{dir.text}}|</b>'
template: '<div text="ignoreme"></div><b *ngFor="let dir of query">{{dir.text}}|</b>'
})
@Injectable()
class NeedsQuery {
@@ -878,7 +897,7 @@ class NeedsFourQueries {
@Component({
selector: 'needs-query-desc',
directives: [NgFor],
template: '<div *ngFor="var dir of query">{{dir.text}}|</div>'
template: '<div *ngFor="let dir of query">{{dir.text}}|</div>'
})
@Injectable()
class NeedsQueryDesc {
@@ -888,7 +907,7 @@ class NeedsQueryDesc {
}
}
@Component({selector: 'needs-query-by-var-binding', directives: [], template: '<ng-content>'})
@Component({selector: 'needs-query-by-ref-binding', directives: [], template: '<ng-content>'})
@Injectable()
class NeedsQueryByLabel {
query: QueryList<any>;
@@ -898,7 +917,7 @@ class NeedsQueryByLabel {
}
@Component({
selector: 'needs-view-query-by-var-binding',
selector: 'needs-view-query-by-ref-binding',
directives: [],
template: '<div #textLabel>text</div>'
})
@@ -908,7 +927,7 @@ class NeedsViewQueryByLabel {
constructor(@ViewQuery("textLabel") query: QueryList<any>) { this.query = query; }
}
@Component({selector: 'needs-query-by-var-bindings', directives: [], template: '<ng-content>'})
@Component({selector: 'needs-query-by-ref-bindings', directives: [], template: '<ng-content>'})
@Injectable()
class NeedsQueryByTwoLabels {
query: QueryList<any>;
@@ -920,7 +939,7 @@ class NeedsQueryByTwoLabels {
@Component({
selector: 'needs-query-and-project',
directives: [NgFor],
template: '<div *ngFor="var dir of query">{{dir.text}}|</div><ng-content></ng-content>'
template: '<div *ngFor="let dir of query">{{dir.text}}|</div><ng-content></ng-content>'
})
@Injectable()
class NeedsQueryAndProject {
@@ -975,7 +994,7 @@ class NeedsViewQueryNestedIf {
selector: 'needs-view-query-order',
directives: [NgFor, TextDirective, InertDirective],
template: '<div text="1"></div>' +
'<div *ngFor="var i of list" [text]="i"></div>' +
'<div *ngFor="let i of list" [text]="i"></div>' +
'<div text="4"></div>'
})
@Injectable()
@@ -992,7 +1011,7 @@ class NeedsViewQueryOrder {
selector: 'needs-view-query-order-with-p',
directives: [NgFor, TextDirective, InertDirective],
template: '<div dir><div text="1"></div>' +
'<div *ngFor="var i of list" [text]="i"></div>' +
'<div *ngFor="let i of list" [text]="i"></div>' +
'<div text="4"></div></div>'
})
@Injectable()
@@ -1005,7 +1024,7 @@ class NeedsViewQueryOrderWithParent {
}
}
@Component({selector: 'needs-tpl', template: '<template var-x="shadow"></template>'})
@Component({selector: 'needs-tpl', template: '<template let-x="shadow"></template>'})
class NeedsTpl {
viewQuery: QueryList<TemplateRef>;
query: QueryList<TemplateRef>;
@@ -1016,6 +1035,13 @@ class NeedsTpl {
}
}
@Component({selector: 'needs-named-tpl', template: '<template #tpl let-x="shadow"></template>'})
class NeedsNamedTpl {
@ViewChild('tpl') viewTpl: TemplateRef;
@ContentChild('tpl') contentTpl: TemplateRef;
constructor(public vc: ViewContainerRef) {}
}
@Component({selector: 'needs-content-children-read', template: ''})
class NeedsContentChildrenWithRead {
@ContentChildren('q', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
@@ -1076,6 +1102,7 @@ class NeedsViewContainerWithRead {
NeedsViewChild,
NeedsContentChild,
NeedsTpl,
NeedsNamedTpl,
TextDirective,
InertDirective,
NgIf,
@@ -1097,4 +1124,4 @@ class MyComp {
this.shouldShow = false;
this.list = ['1d', '2d', '3d'];
}
}
}
@@ -92,6 +92,7 @@ class _ArrayLogger {
class DummyConsole implements Console {
log(message) {}
warn(message) {}
}
export function main() {
+1
View File
@@ -116,6 +116,7 @@ var NG_COMPILER = [
"TEMPLATE_TRANSFORMS",
"TextAst",
"VariableAst",
"ReferenceAst",
"XHR",
"templateVisitAll",
"CompileDiDependencyMetadata",
@@ -43,6 +43,7 @@ import {MockApplicationRef} from 'angular2/src/mock/mock_application_ref';
class DummyConsole implements Console {
log(message) {}
warn(message) {}
}
export function main() {
@@ -35,6 +35,7 @@ class _ArrayLogger {
class DummyConsole implements Console {
log(message) {}
warn(message) {}
}
export function main() {