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:
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user