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:
parent
ff2ae7a2e1
commit
d2efac18ed
|
@ -14,7 +14,7 @@ Removes or recreates a portion of the DOM tree based on the showSection expressi
|
||||||
|
|
||||||
@cheatsheetItem
|
@cheatsheetItem
|
||||||
syntax:
|
syntax:
|
||||||
`<li *ngFor="#item of list">`|`*ngFor`
|
`<li *ngFor="let item of list">`|`*ngFor`
|
||||||
description:
|
description:
|
||||||
Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.
|
Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.
|
||||||
|
|
||||||
|
|
|
@ -433,7 +433,7 @@ Finally, we can move the `ngFor` keyword to the left hand side and prefix it wit
|
||||||
|
|
||||||
```
|
```
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="var person of people; var i=index">{{i}}. {{person}}<li>
|
<li *ngFor="let person of people; var i=index">{{i}}. {{person}}<li>
|
||||||
</ul>
|
</ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ Let's start with a View such as:
|
||||||
|
|
||||||
```
|
```
|
||||||
<ul>
|
<ul>
|
||||||
<li template="ngFor: #person of people">{{person}}</li>
|
<li template="ngFor: let person of people">{{person}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ export class SlicePipeStringExample {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'slice-list-example',
|
selector: 'slice-list-example',
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<li *ngFor="var i of collection | slice:1:3">{{i}}</li>
|
<li *ngFor="let i of collection | slice:1:3">{{i}}</li>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
export class SlicePipeListExample {
|
export class SlicePipeListExample {
|
||||||
|
|
|
@ -36,7 +36,7 @@ class MyCmp implements OnDeactivate {
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
<div id="log">
|
<div id="log">
|
||||||
<h2>Log:</h2>
|
<h2>Log:</h2>
|
||||||
<p *ngFor="#logItem of logService.logs">{{ logItem }}</p>
|
<p *ngFor="let logItem of logService.logs">{{ logItem }}</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
directives: [ROUTER_DIRECTIVES]
|
directives: [ROUTER_DIRECTIVES]
|
||||||
|
|
|
@ -56,7 +56,7 @@ export {URLSearchParams} from './src/http/url_search_params';
|
||||||
* <div>
|
* <div>
|
||||||
* <h1>People</h1>
|
* <h1>People</h1>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#person of people">
|
* <li *ngFor="let person of people">
|
||||||
* {{person.name}}
|
* {{person.name}}
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
@ -194,7 +194,7 @@ export const HTTP_BINDINGS = HTTP_PROVIDERS;
|
||||||
* <div>
|
* <div>
|
||||||
* <h1>People</h1>
|
* <h1>People</h1>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#person of people">
|
* <li *ngFor="let person of people">
|
||||||
* {{person.name}}
|
* {{person.name}}
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
|
|
@ -58,7 +58,7 @@ import {BaseException} from "../../facade/exceptions";
|
||||||
*
|
*
|
||||||
* ### Syntax
|
* ### Syntax
|
||||||
*
|
*
|
||||||
* - `<li *ngFor="#item of items; #i = index">...</li>`
|
* - `<li *ngFor="let item of items; #i = index">...</li>`
|
||||||
* - `<li template="ngFor #item of items; #i = index">...</li>`
|
* - `<li template="ngFor #item of items; #i = index">...</li>`
|
||||||
* - `<template ngFor #item [ngForOf]="items" #i="index"><li>...</li></template>`
|
* - `<template ngFor #item [ngForOf]="items" #i="index"><li>...</li></template>`
|
||||||
*
|
*
|
||||||
|
|
|
@ -96,7 +96,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* <select ngControl="city">
|
* <select ngControl="city">
|
||||||
* <option *ngFor="#c of cities" [value]="c"></option>
|
* <option *ngFor="let c of cities" [value]="c"></option>
|
||||||
* </select>
|
* </select>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,7 +46,11 @@ export class Token {
|
||||||
|
|
||||||
isKeyword(): boolean { return (this.type == TokenType.Keyword); }
|
isKeyword(): boolean { return (this.type == TokenType.Keyword); }
|
||||||
|
|
||||||
isKeywordVar(): boolean { return (this.type == TokenType.Keyword && this.strValue == "var"); }
|
isKeywordDeprecatedVar(): boolean {
|
||||||
|
return (this.type == TokenType.Keyword && this.strValue == "var");
|
||||||
|
}
|
||||||
|
|
||||||
|
isKeywordLet(): boolean { return (this.type == TokenType.Keyword && this.strValue == "let"); }
|
||||||
|
|
||||||
isKeywordNull(): boolean { return (this.type == TokenType.Keyword && this.strValue == "null"); }
|
isKeywordNull(): boolean { return (this.type == TokenType.Keyword && this.strValue == "null"); }
|
||||||
|
|
||||||
|
@ -464,4 +468,4 @@ var OPERATORS = SetWrapper.createFromList([
|
||||||
|
|
||||||
|
|
||||||
var KEYWORDS =
|
var KEYWORDS =
|
||||||
SetWrapper.createFromList(['var', 'null', 'undefined', 'true', 'false', 'if', 'else']);
|
SetWrapper.createFromList(['var', 'let', 'null', 'undefined', 'true', 'false', 'if', 'else']);
|
||||||
|
|
|
@ -62,6 +62,10 @@ export class SplitInterpolation {
|
||||||
constructor(public strings: string[], public expressions: string[]) {}
|
constructor(public strings: string[], public expressions: string[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TemplateBindingParseResult {
|
||||||
|
constructor(public templateBindings: TemplateBinding[], public warnings: string[]) {}
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Parser {
|
export class Parser {
|
||||||
constructor(/** @internal */
|
constructor(/** @internal */
|
||||||
|
@ -112,7 +116,7 @@ export class Parser {
|
||||||
return new Quote(prefix, uninterpretedExpression, location);
|
return new Quote(prefix, uninterpretedExpression, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseTemplateBindings(input: string, location: any): TemplateBinding[] {
|
parseTemplateBindings(input: string, location: any): TemplateBindingParseResult {
|
||||||
var tokens = this._lexer.tokenize(input);
|
var tokens = this._lexer.tokenize(input);
|
||||||
return new _ParseAST(input, location, tokens, false).parseTemplateBindings();
|
return new _ParseAST(input, location, tokens, false).parseTemplateBindings();
|
||||||
}
|
}
|
||||||
|
@ -228,16 +232,11 @@ export class _ParseAST {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optionalKeywordVar(): boolean {
|
peekKeywordLet(): boolean { return this.next.isKeywordLet(); }
|
||||||
if (this.peekKeywordVar()) {
|
|
||||||
this.advance();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peekKeywordVar(): boolean { return this.next.isKeywordVar() || this.next.isOperator('#'); }
|
peekDeprecatedKeywordVar(): boolean { return this.next.isKeywordDeprecatedVar(); }
|
||||||
|
|
||||||
|
peekDeprecatedOperatorHash(): boolean { return this.next.isOperator('#'); }
|
||||||
|
|
||||||
expectCharacter(code: number) {
|
expectCharacter(code: number) {
|
||||||
if (this.optionalCharacter(code)) return;
|
if (this.optionalCharacter(code)) return;
|
||||||
|
@ -617,11 +616,23 @@ export class _ParseAST {
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseTemplateBindings(): any[] {
|
parseTemplateBindings(): TemplateBindingParseResult {
|
||||||
var bindings = [];
|
var bindings: TemplateBinding[] = [];
|
||||||
var prefix = null;
|
var prefix = null;
|
||||||
|
var warnings: string[] = [];
|
||||||
while (this.index < this.tokens.length) {
|
while (this.index < this.tokens.length) {
|
||||||
var keyIsVar: boolean = this.optionalKeywordVar();
|
var keyIsVar: boolean = this.peekKeywordLet();
|
||||||
|
if (!keyIsVar && this.peekDeprecatedKeywordVar()) {
|
||||||
|
keyIsVar = true;
|
||||||
|
warnings.push(`"var" inside of expressions is deprecated. Use "let" instead!`);
|
||||||
|
}
|
||||||
|
if (!keyIsVar && this.peekDeprecatedOperatorHash()) {
|
||||||
|
keyIsVar = true;
|
||||||
|
warnings.push(`"#" inside of expressions is deprecated. Use "let" instead!`);
|
||||||
|
}
|
||||||
|
if (keyIsVar) {
|
||||||
|
this.advance();
|
||||||
|
}
|
||||||
var key = this.expectTemplateBindingKey();
|
var key = this.expectTemplateBindingKey();
|
||||||
if (!keyIsVar) {
|
if (!keyIsVar) {
|
||||||
if (prefix == null) {
|
if (prefix == null) {
|
||||||
|
@ -639,7 +650,8 @@ export class _ParseAST {
|
||||||
} else {
|
} else {
|
||||||
name = '\$implicit';
|
name = '\$implicit';
|
||||||
}
|
}
|
||||||
} else if (this.next !== EOF && !this.peekKeywordVar()) {
|
} else if (this.next !== EOF && !this.peekKeywordLet() && !this.peekDeprecatedKeywordVar() &&
|
||||||
|
!this.peekDeprecatedOperatorHash()) {
|
||||||
var start = this.inputIndex;
|
var start = this.inputIndex;
|
||||||
var ast = this.parsePipe();
|
var ast = this.parsePipe();
|
||||||
var source = this.input.substring(start, this.inputIndex);
|
var source = this.input.substring(start, this.inputIndex);
|
||||||
|
@ -650,7 +662,7 @@ export class _ParseAST {
|
||||||
this.optionalCharacter($COMMA);
|
this.optionalCharacter($COMMA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bindings;
|
return new TemplateBindingParseResult(bindings, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(message: string, index: number = null) {
|
error(message: string, index: number = null) {
|
||||||
|
|
|
@ -17,8 +17,14 @@ export class ParseSourceSpan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ParseErrorLevel {
|
||||||
|
WARNING,
|
||||||
|
FATAL
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class ParseError {
|
export abstract class ParseError {
|
||||||
constructor(public span: ParseSourceSpan, public msg: string) {}
|
constructor(public span: ParseSourceSpan, public msg: string,
|
||||||
|
public level: ParseErrorLevel = ParseErrorLevel.FATAL) {}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
var source = this.span.start.file.content;
|
var source = this.span.start.file.content;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
NgContentAst,
|
NgContentAst,
|
||||||
EmbeddedTemplateAst,
|
EmbeddedTemplateAst,
|
||||||
ElementAst,
|
ElementAst,
|
||||||
VariableAst,
|
ReferenceAst,
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
AttrAst,
|
AttrAst,
|
||||||
|
@ -69,7 +69,7 @@ export class ProviderElementContext {
|
||||||
|
|
||||||
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
|
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
|
||||||
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
|
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
|
||||||
attrs: AttrAst[], vars: VariableAst[], private _sourceSpan: ParseSourceSpan) {
|
attrs: AttrAst[], refs: ReferenceAst[], private _sourceSpan: ParseSourceSpan) {
|
||||||
this._attrs = {};
|
this._attrs = {};
|
||||||
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
|
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
|
||||||
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
|
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
|
||||||
|
@ -79,9 +79,8 @@ export class ProviderElementContext {
|
||||||
var queriedTokens = new CompileTokenMap<boolean>();
|
var queriedTokens = new CompileTokenMap<boolean>();
|
||||||
this._allProviders.values().forEach(
|
this._allProviders.values().forEach(
|
||||||
(provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
|
(provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
|
||||||
vars.forEach((varAst) => {
|
refs.forEach((refAst) => {
|
||||||
var varToken = new CompileTokenMetadata({value: varAst.name});
|
this._addQueryReadsTo(new CompileTokenMetadata({value: refAst.name}), queriedTokens);
|
||||||
this._addQueryReadsTo(varToken, queriedTokens);
|
|
||||||
});
|
});
|
||||||
if (isPresent(queriedTokens.get(identifierToken(Identifiers.ViewContainerRef)))) {
|
if (isPresent(queriedTokens.get(identifierToken(Identifiers.ViewContainerRef)))) {
|
||||||
this._hasViewContainer = true;
|
this._hasViewContainer = true;
|
||||||
|
|
|
@ -30,7 +30,6 @@ import {
|
||||||
NgContentAst,
|
NgContentAst,
|
||||||
EmbeddedTemplateAst,
|
EmbeddedTemplateAst,
|
||||||
ElementAst,
|
ElementAst,
|
||||||
VariableAst,
|
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
AttrAst,
|
AttrAst,
|
||||||
|
|
|
@ -82,7 +82,18 @@ export class BoundEventAst implements TemplateAst {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A variable declaration on an element (e.g. `#var="expression"`).
|
* A reference declaration on an element (e.g. `let someName="expression"`).
|
||||||
|
*/
|
||||||
|
export class ReferenceAst implements TemplateAst {
|
||||||
|
constructor(public name: string, public value: CompileTokenMetadata,
|
||||||
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
|
return visitor.visitReference(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A variable declaration on a <template> (e.g. `var-someName="someLocalName"`).
|
||||||
*/
|
*/
|
||||||
export class VariableAst implements TemplateAst {
|
export class VariableAst implements TemplateAst {
|
||||||
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
@ -97,7 +108,7 @@ export class VariableAst implements TemplateAst {
|
||||||
export class ElementAst implements TemplateAst {
|
export class ElementAst implements TemplateAst {
|
||||||
constructor(public name: string, public attrs: AttrAst[],
|
constructor(public name: string, public attrs: AttrAst[],
|
||||||
public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[],
|
public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[],
|
||||||
public exportAsVars: VariableAst[], public directives: DirectiveAst[],
|
public references: ReferenceAst[], public directives: DirectiveAst[],
|
||||||
public providers: ProviderAst[], public hasViewContainer: boolean,
|
public providers: ProviderAst[], public hasViewContainer: boolean,
|
||||||
public children: TemplateAst[], public ngContentIndex: number,
|
public children: TemplateAst[], public ngContentIndex: number,
|
||||||
public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
|
@ -106,14 +117,6 @@ export class ElementAst implements TemplateAst {
|
||||||
return visitor.visitElement(this, context);
|
return visitor.visitElement(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the element has any active bindings (inputs, outputs, vars, or directives).
|
|
||||||
*/
|
|
||||||
isBound(): boolean {
|
|
||||||
return (this.inputs.length > 0 || this.outputs.length > 0 || this.exportAsVars.length > 0 ||
|
|
||||||
this.directives.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the component associated with this element, if any.
|
* Get the component associated with this element, if any.
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +135,8 @@ export class ElementAst implements TemplateAst {
|
||||||
* A `<template>` element included in an Angular template.
|
* A `<template>` element included in an Angular template.
|
||||||
*/
|
*/
|
||||||
export class EmbeddedTemplateAst implements TemplateAst {
|
export class EmbeddedTemplateAst implements TemplateAst {
|
||||||
constructor(public attrs: AttrAst[], public outputs: BoundEventAst[], public vars: VariableAst[],
|
constructor(public attrs: AttrAst[], public outputs: BoundEventAst[],
|
||||||
|
public references: ReferenceAst[], public variables: VariableAst[],
|
||||||
public directives: DirectiveAst[], public providers: ProviderAst[],
|
public directives: DirectiveAst[], public providers: ProviderAst[],
|
||||||
public hasViewContainer: boolean, public children: TemplateAst[],
|
public hasViewContainer: boolean, public children: TemplateAst[],
|
||||||
public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
@ -160,7 +164,7 @@ export class DirectiveAst implements TemplateAst {
|
||||||
constructor(public directive: CompileDirectiveMetadata,
|
constructor(public directive: CompileDirectiveMetadata,
|
||||||
public inputs: BoundDirectivePropertyAst[],
|
public inputs: BoundDirectivePropertyAst[],
|
||||||
public hostProperties: BoundElementPropertyAst[], public hostEvents: BoundEventAst[],
|
public hostProperties: BoundElementPropertyAst[], public hostEvents: BoundEventAst[],
|
||||||
public exportAsVars: VariableAst[], public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
return visitor.visitDirective(this, context);
|
return visitor.visitDirective(this, context);
|
||||||
}
|
}
|
||||||
|
@ -232,6 +236,7 @@ export interface TemplateAstVisitor {
|
||||||
visitNgContent(ast: NgContentAst, context: any): any;
|
visitNgContent(ast: NgContentAst, context: any): any;
|
||||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any;
|
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any;
|
||||||
visitElement(ast: ElementAst, context: any): any;
|
visitElement(ast: ElementAst, context: any): any;
|
||||||
|
visitReference(ast: ReferenceAst, context: any): any;
|
||||||
visitVariable(ast: VariableAst, context: any): any;
|
visitVariable(ast: VariableAst, context: any): any;
|
||||||
visitEvent(ast: BoundEventAst, context: any): any;
|
visitEvent(ast: BoundEventAst, context: any): any;
|
||||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any;
|
visitElementProperty(ast: BoundElementPropertyAst, context: any): any;
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
isArray
|
isArray
|
||||||
} from 'angular2/src/facade/lang';
|
} from 'angular2/src/facade/lang';
|
||||||
import {Injectable, Inject, OpaqueToken, Optional} from 'angular2/core';
|
import {Injectable, Inject, OpaqueToken, Optional} from 'angular2/core';
|
||||||
|
import {Console} from 'angular2/src/core/console';
|
||||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||||
import {
|
import {
|
||||||
AST,
|
AST,
|
||||||
|
@ -34,14 +35,14 @@ import {
|
||||||
} from './compile_metadata';
|
} from './compile_metadata';
|
||||||
import {HtmlParser} from './html_parser';
|
import {HtmlParser} from './html_parser';
|
||||||
import {splitNsName, mergeNsAndName} from './html_tags';
|
import {splitNsName, mergeNsAndName} from './html_tags';
|
||||||
import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util';
|
import {ParseSourceSpan, ParseError, ParseLocation, ParseErrorLevel} from './parse_util';
|
||||||
import {MAX_INTERPOLATION_VALUES} from 'angular2/src/core/linker/view_utils';
|
import {MAX_INTERPOLATION_VALUES} from 'angular2/src/core/linker/view_utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ElementAst,
|
ElementAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
VariableAst,
|
ReferenceAst,
|
||||||
TemplateAst,
|
TemplateAst,
|
||||||
TemplateAstVisitor,
|
TemplateAstVisitor,
|
||||||
templateVisitAll,
|
templateVisitAll,
|
||||||
|
@ -54,7 +55,8 @@ import {
|
||||||
DirectiveAst,
|
DirectiveAst,
|
||||||
BoundDirectivePropertyAst,
|
BoundDirectivePropertyAst,
|
||||||
ProviderAst,
|
ProviderAst,
|
||||||
ProviderAstType
|
ProviderAstType,
|
||||||
|
VariableAst
|
||||||
} from './template_ast';
|
} from './template_ast';
|
||||||
import {CssSelector, SelectorMatcher} from 'angular2/src/compiler/selector';
|
import {CssSelector, SelectorMatcher} from 'angular2/src/compiler/selector';
|
||||||
|
|
||||||
|
@ -76,19 +78,22 @@ import {
|
||||||
} from './html_ast';
|
} from './html_ast';
|
||||||
|
|
||||||
import {splitAtColon} from './util';
|
import {splitAtColon} from './util';
|
||||||
|
import {identifierToken, Identifiers} from './identifiers';
|
||||||
|
|
||||||
import {ProviderElementContext, ProviderViewContext} from './provider_parser';
|
import {ProviderElementContext, ProviderViewContext} from './provider_parser';
|
||||||
|
|
||||||
// Group 1 = "bind-"
|
// Group 1 = "bind-"
|
||||||
// Group 2 = "var-" or "#"
|
// Group 2 = "var-"
|
||||||
// Group 3 = "on-"
|
// Group 3 = "let-"
|
||||||
// Group 4 = "bindon-"
|
// Group 4 = "ref-/#"
|
||||||
// Group 5 = the identifier after "bind-", "var-/#", or "on-"
|
// Group 5 = "on-"
|
||||||
// Group 6 = identifier inside [()]
|
// Group 6 = "bindon-"
|
||||||
// Group 7 = identifier inside []
|
// Group 7 = the identifier after "bind-", "var-/#", or "on-"
|
||||||
// Group 8 = identifier inside ()
|
// Group 8 = identifier inside [()]
|
||||||
|
// Group 9 = identifier inside []
|
||||||
|
// Group 10 = identifier inside ()
|
||||||
var BIND_NAME_REGEXP =
|
var BIND_NAME_REGEXP =
|
||||||
/^(?:(?:(?:(bind-)|(var-|#)|(on-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g;
|
/^(?:(?:(?:(bind-)|(var-)|(let-)|(ref-|#)|(on-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g;
|
||||||
|
|
||||||
const TEMPLATE_ELEMENT = 'template';
|
const TEMPLATE_ELEMENT = 'template';
|
||||||
const TEMPLATE_ATTR = 'template';
|
const TEMPLATE_ATTR = 'template';
|
||||||
|
@ -112,7 +117,9 @@ var TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
|
||||||
export const TEMPLATE_TRANSFORMS = CONST_EXPR(new OpaqueToken('TemplateTransforms'));
|
export const TEMPLATE_TRANSFORMS = CONST_EXPR(new OpaqueToken('TemplateTransforms'));
|
||||||
|
|
||||||
export class TemplateParseError extends ParseError {
|
export class TemplateParseError extends ParseError {
|
||||||
constructor(message: string, span: ParseSourceSpan) { super(span, message); }
|
constructor(message: string, span: ParseSourceSpan, level: ParseErrorLevel) {
|
||||||
|
super(span, message, level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TemplateParseResult {
|
export class TemplateParseResult {
|
||||||
|
@ -122,15 +129,20 @@ export class TemplateParseResult {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TemplateParser {
|
export class TemplateParser {
|
||||||
constructor(private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry,
|
constructor(private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry,
|
||||||
private _htmlParser: HtmlParser,
|
private _htmlParser: HtmlParser, private _console: Console,
|
||||||
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
||||||
|
|
||||||
parse(component: CompileDirectiveMetadata, template: string,
|
parse(component: CompileDirectiveMetadata, template: string,
|
||||||
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||||
templateUrl: string): TemplateAst[] {
|
templateUrl: string): TemplateAst[] {
|
||||||
var result = this.tryParse(component, template, directives, pipes, templateUrl);
|
var result = this.tryParse(component, template, directives, pipes, templateUrl);
|
||||||
if (isPresent(result.errors)) {
|
var warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
|
||||||
var errorString = result.errors.join('\n');
|
var errors = result.errors.filter(error => error.level === ParseErrorLevel.FATAL);
|
||||||
|
if (warnings.length > 0) {
|
||||||
|
this._console.warn(`Template parse warnings:\n${warnings.join('\n')}`);
|
||||||
|
}
|
||||||
|
if (errors.length > 0) {
|
||||||
|
var errorString = errors.join('\n');
|
||||||
throw new BaseException(`Template parse errors:\n${errorString}`);
|
throw new BaseException(`Template parse errors:\n${errorString}`);
|
||||||
}
|
}
|
||||||
return result.templateAst;
|
return result.templateAst;
|
||||||
|
@ -162,7 +174,7 @@ export class TemplateParser {
|
||||||
this.transforms.forEach(
|
this.transforms.forEach(
|
||||||
(transform: TemplateAstVisitor) => { result = templateVisitAll(transform, result); });
|
(transform: TemplateAstVisitor) => { result = templateVisitAll(transform, result); });
|
||||||
}
|
}
|
||||||
return new TemplateParseResult(result);
|
return new TemplateParseResult(result, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +199,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _reportError(message: string, sourceSpan: ParseSourceSpan) {
|
private _reportError(message: string, sourceSpan: ParseSourceSpan,
|
||||||
this.errors.push(new TemplateParseError(message, sourceSpan));
|
level: ParseErrorLevel = ParseErrorLevel.FATAL) {
|
||||||
|
this.errors.push(new TemplateParseError(message, sourceSpan, level));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _parseInterpolation(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
|
private _parseInterpolation(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
|
||||||
|
@ -235,13 +248,15 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
private _parseTemplateBindings(value: string, sourceSpan: ParseSourceSpan): TemplateBinding[] {
|
private _parseTemplateBindings(value: string, sourceSpan: ParseSourceSpan): TemplateBinding[] {
|
||||||
var sourceInfo = sourceSpan.start.toString();
|
var sourceInfo = sourceSpan.start.toString();
|
||||||
try {
|
try {
|
||||||
var bindings = this._exprParser.parseTemplateBindings(value, sourceInfo);
|
var bindingsResult = this._exprParser.parseTemplateBindings(value, sourceInfo);
|
||||||
bindings.forEach((binding) => {
|
bindingsResult.templateBindings.forEach((binding) => {
|
||||||
if (isPresent(binding.expression)) {
|
if (isPresent(binding.expression)) {
|
||||||
this._checkPipes(binding.expression, sourceSpan);
|
this._checkPipes(binding.expression, sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return bindings;
|
bindingsResult.warnings.forEach(
|
||||||
|
(warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); });
|
||||||
|
return bindingsResult.templateBindings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._reportError(`${e}`, sourceSpan);
|
this._reportError(`${e}`, sourceSpan);
|
||||||
return [];
|
return [];
|
||||||
|
@ -299,19 +314,25 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
|
|
||||||
var matchableAttrs: string[][] = [];
|
var matchableAttrs: string[][] = [];
|
||||||
var elementOrDirectiveProps: BoundElementOrDirectiveProperty[] = [];
|
var elementOrDirectiveProps: BoundElementOrDirectiveProperty[] = [];
|
||||||
var vars: VariableAst[] = [];
|
var elementOrDirectiveRefs: ElementOrDirectiveRef[] = [];
|
||||||
|
var elementVars: VariableAst[] = [];
|
||||||
var events: BoundEventAst[] = [];
|
var events: BoundEventAst[] = [];
|
||||||
|
|
||||||
var templateElementOrDirectiveProps: BoundElementOrDirectiveProperty[] = [];
|
var templateElementOrDirectiveProps: BoundElementOrDirectiveProperty[] = [];
|
||||||
var templateVars: VariableAst[] = [];
|
|
||||||
var templateMatchableAttrs: string[][] = [];
|
var templateMatchableAttrs: string[][] = [];
|
||||||
|
var templateElementVars: VariableAst[] = [];
|
||||||
|
|
||||||
var hasInlineTemplates = false;
|
var hasInlineTemplates = false;
|
||||||
var attrs = [];
|
var attrs = [];
|
||||||
|
var lcElName = splitNsName(nodeName.toLowerCase())[1];
|
||||||
|
var isTemplateElement = lcElName == TEMPLATE_ELEMENT;
|
||||||
|
|
||||||
element.attrs.forEach(attr => {
|
element.attrs.forEach(attr => {
|
||||||
var hasBinding = this._parseAttr(attr, matchableAttrs, elementOrDirectiveProps, events, vars);
|
var hasBinding =
|
||||||
|
this._parseAttr(isTemplateElement, attr, matchableAttrs, elementOrDirectiveProps, events,
|
||||||
|
elementOrDirectiveRefs, elementVars);
|
||||||
var hasTemplateBinding = this._parseInlineTemplateBinding(
|
var hasTemplateBinding = this._parseInlineTemplateBinding(
|
||||||
attr, templateMatchableAttrs, templateElementOrDirectiveProps, templateVars);
|
attr, templateMatchableAttrs, templateElementOrDirectiveProps, templateElementVars);
|
||||||
if (!hasBinding && !hasTemplateBinding) {
|
if (!hasBinding && !hasTemplateBinding) {
|
||||||
// don't include the bindings as attributes as well in the AST
|
// don't include the bindings as attributes as well in the AST
|
||||||
attrs.push(this.visitAttr(attr, null));
|
attrs.push(this.visitAttr(attr, null));
|
||||||
|
@ -322,19 +343,18 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var lcElName = splitNsName(nodeName.toLowerCase())[1];
|
|
||||||
var isTemplateElement = lcElName == TEMPLATE_ELEMENT;
|
|
||||||
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
|
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
|
||||||
var directiveMetas = this._parseDirectives(this.selectorMatcher, elementCssSelector);
|
var directiveMetas = this._parseDirectives(this.selectorMatcher, elementCssSelector);
|
||||||
var directiveAsts =
|
var references: ReferenceAst[] = [];
|
||||||
this._createDirectiveAsts(element.name, directiveMetas, elementOrDirectiveProps,
|
var directiveAsts = this._createDirectiveAsts(isTemplateElement, element.name, directiveMetas,
|
||||||
isTemplateElement ? [] : vars, element.sourceSpan);
|
elementOrDirectiveProps, elementOrDirectiveRefs,
|
||||||
|
element.sourceSpan, references);
|
||||||
var elementProps: BoundElementPropertyAst[] =
|
var elementProps: BoundElementPropertyAst[] =
|
||||||
this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directiveAsts);
|
this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directiveAsts);
|
||||||
var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
||||||
var providerContext =
|
var providerContext =
|
||||||
new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot,
|
new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot,
|
||||||
directiveAsts, attrs, vars, element.sourceSpan);
|
directiveAsts, attrs, references, element.sourceSpan);
|
||||||
var children = htmlVisitAll(
|
var children = htmlVisitAll(
|
||||||
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
||||||
ElementContext.create(isTemplateElement, directiveAsts,
|
ElementContext.create(isTemplateElement, directiveAsts,
|
||||||
|
@ -362,17 +382,15 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
element.sourceSpan);
|
element.sourceSpan);
|
||||||
|
|
||||||
parsedElement = new EmbeddedTemplateAst(
|
parsedElement = new EmbeddedTemplateAst(
|
||||||
attrs, events, vars, providerContext.transformedDirectiveAsts,
|
attrs, events, references, elementVars, providerContext.transformedDirectiveAsts,
|
||||||
providerContext.transformProviders, providerContext.transformedHasViewContainer, children,
|
providerContext.transformProviders, providerContext.transformedHasViewContainer, children,
|
||||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||||
} else {
|
} else {
|
||||||
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
|
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
|
||||||
var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0);
|
|
||||||
let ngContentIndex =
|
let ngContentIndex =
|
||||||
hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
|
hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector);
|
||||||
|
|
||||||
parsedElement = new ElementAst(
|
parsedElement = new ElementAst(
|
||||||
nodeName, attrs, elementProps, events, elementExportAsVars,
|
nodeName, attrs, elementProps, events, references,
|
||||||
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
|
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
|
||||||
providerContext.transformedHasViewContainer, children,
|
providerContext.transformedHasViewContainer, children,
|
||||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||||
|
@ -381,18 +399,18 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
|
var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
|
||||||
var templateDirectiveMetas = this._parseDirectives(this.selectorMatcher, templateCssSelector);
|
var templateDirectiveMetas = this._parseDirectives(this.selectorMatcher, templateCssSelector);
|
||||||
var templateDirectiveAsts =
|
var templateDirectiveAsts =
|
||||||
this._createDirectiveAsts(element.name, templateDirectiveMetas,
|
this._createDirectiveAsts(true, element.name, templateDirectiveMetas,
|
||||||
templateElementOrDirectiveProps, [], element.sourceSpan);
|
templateElementOrDirectiveProps, [], element.sourceSpan, []);
|
||||||
var templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
var templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts(
|
||||||
element.name, templateElementOrDirectiveProps, templateDirectiveAsts);
|
element.name, templateElementOrDirectiveProps, templateDirectiveAsts);
|
||||||
this._assertNoComponentsNorElementBindingsOnTemplate(
|
this._assertNoComponentsNorElementBindingsOnTemplate(
|
||||||
templateDirectiveAsts, templateElementProps, element.sourceSpan);
|
templateDirectiveAsts, templateElementProps, element.sourceSpan);
|
||||||
var templateProviderContext = new ProviderElementContext(
|
var templateProviderContext = new ProviderElementContext(
|
||||||
this.providerViewContext, parent.providerContext, parent.isTemplateElement,
|
this.providerViewContext, parent.providerContext, parent.isTemplateElement,
|
||||||
templateDirectiveAsts, [], templateVars, element.sourceSpan);
|
templateDirectiveAsts, [], [], element.sourceSpan);
|
||||||
templateProviderContext.afterElement();
|
templateProviderContext.afterElement();
|
||||||
|
|
||||||
parsedElement = new EmbeddedTemplateAst([], [], templateVars,
|
parsedElement = new EmbeddedTemplateAst([], [], [], templateElementVars,
|
||||||
templateProviderContext.transformedDirectiveAsts,
|
templateProviderContext.transformedDirectiveAsts,
|
||||||
templateProviderContext.transformProviders,
|
templateProviderContext.transformProviders,
|
||||||
templateProviderContext.transformedHasViewContainer,
|
templateProviderContext.transformedHasViewContainer,
|
||||||
|
@ -417,7 +435,6 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
var binding = bindings[i];
|
var binding = bindings[i];
|
||||||
if (binding.keyIsVar) {
|
if (binding.keyIsVar) {
|
||||||
targetVars.push(new VariableAst(binding.key, binding.name, attr.sourceSpan));
|
targetVars.push(new VariableAst(binding.key, binding.name, attr.sourceSpan));
|
||||||
targetMatchableAttrs.push([binding.key, binding.name]);
|
|
||||||
} else if (isPresent(binding.expression)) {
|
} else if (isPresent(binding.expression)) {
|
||||||
this._parsePropertyAst(binding.key, binding.expression, attr.sourceSpan,
|
this._parsePropertyAst(binding.key, binding.expression, attr.sourceSpan,
|
||||||
targetMatchableAttrs, targetProps);
|
targetMatchableAttrs, targetProps);
|
||||||
|
@ -431,9 +448,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _parseAttr(attr: HtmlAttrAst, targetMatchableAttrs: string[][],
|
private _parseAttr(isTemplateElement: boolean, attr: HtmlAttrAst,
|
||||||
|
targetMatchableAttrs: string[][],
|
||||||
targetProps: BoundElementOrDirectiveProperty[], targetEvents: BoundEventAst[],
|
targetProps: BoundElementOrDirectiveProperty[], targetEvents: BoundEventAst[],
|
||||||
targetVars: VariableAst[]): boolean {
|
targetRefs: ElementOrDirectiveRef[], targetVars: VariableAst[]): boolean {
|
||||||
var attrName = this._normalizeAttributeName(attr.name);
|
var attrName = this._normalizeAttributeName(attr.name);
|
||||||
var attrValue = attr.value;
|
var attrValue = attr.value;
|
||||||
var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName);
|
var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName);
|
||||||
|
@ -441,36 +459,55 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
if (isPresent(bindParts)) {
|
if (isPresent(bindParts)) {
|
||||||
hasBinding = true;
|
hasBinding = true;
|
||||||
if (isPresent(bindParts[1])) { // match: bind-prop
|
if (isPresent(bindParts[1])) { // match: bind-prop
|
||||||
this._parseProperty(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetProps);
|
|
||||||
|
|
||||||
} else if (isPresent(
|
|
||||||
bindParts[2])) { // match: var-name / var-name="iden" / #name / #name="iden"
|
|
||||||
var identifier = bindParts[5];
|
|
||||||
this._parseVariable(identifier, attrValue, attr.sourceSpan, targetVars);
|
|
||||||
|
|
||||||
} else if (isPresent(bindParts[3])) { // match: on-event
|
|
||||||
this._parseEvent(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetEvents);
|
|
||||||
|
|
||||||
} else if (isPresent(bindParts[4])) { // match: bindon-prop
|
|
||||||
this._parseProperty(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetProps);
|
|
||||||
this._parseAssignmentEvent(bindParts[5], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetEvents);
|
|
||||||
|
|
||||||
} else if (isPresent(bindParts[6])) { // match: [(expr)]
|
|
||||||
this._parseProperty(bindParts[6], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetProps);
|
|
||||||
this._parseAssignmentEvent(bindParts[6], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
|
||||||
targetEvents);
|
|
||||||
|
|
||||||
} else if (isPresent(bindParts[7])) { // match: [expr]
|
|
||||||
this._parseProperty(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
this._parseProperty(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
targetProps);
|
targetProps);
|
||||||
|
|
||||||
} else if (isPresent(bindParts[8])) { // match: (event)
|
} else if (isPresent(bindParts[2])) { // match: var-name / var-name="iden"
|
||||||
this._parseEvent(bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
var identifier = bindParts[7];
|
||||||
|
if (isTemplateElement) {
|
||||||
|
this._reportError(`"var-" on <template> elements is deprecated. Use "let-" instead!`,
|
||||||
|
attr.sourceSpan, ParseErrorLevel.WARNING);
|
||||||
|
this._parseVariable(identifier, attrValue, attr.sourceSpan, targetVars);
|
||||||
|
} else {
|
||||||
|
this._reportError(`"var-" on non <template> elements is deprecated. Use "ref-" instead!`,
|
||||||
|
attr.sourceSpan, ParseErrorLevel.WARNING);
|
||||||
|
this._parseReference(identifier, attrValue, attr.sourceSpan, targetRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[3])) { // match: let-name
|
||||||
|
if (isTemplateElement) {
|
||||||
|
var identifier = bindParts[7];
|
||||||
|
this._parseVariable(identifier, attrValue, attr.sourceSpan, targetVars);
|
||||||
|
} else {
|
||||||
|
this._reportError(`"let-" is only supported on template elements.`, attr.sourceSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[4])) { // match: ref- / #iden
|
||||||
|
var identifier = bindParts[7];
|
||||||
|
this._parseReference(identifier, attrValue, attr.sourceSpan, targetRefs);
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[5])) { // match: on-event
|
||||||
|
this._parseEvent(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetEvents);
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[6])) { // match: bindon-prop
|
||||||
|
this._parseProperty(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetProps);
|
||||||
|
this._parseAssignmentEvent(bindParts[7], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetEvents);
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[8])) { // match: [(expr)]
|
||||||
|
this._parseProperty(bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetProps);
|
||||||
|
this._parseAssignmentEvent(bindParts[8], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetEvents);
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[9])) { // match: [expr]
|
||||||
|
this._parseProperty(bindParts[9], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
|
targetProps);
|
||||||
|
|
||||||
|
} else if (isPresent(bindParts[10])) { // match: (event)
|
||||||
|
this._parseEvent(bindParts[10], attrValue, attr.sourceSpan, targetMatchableAttrs,
|
||||||
targetEvents);
|
targetEvents);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -495,6 +532,14 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _parseReference(identifier: string, value: string, sourceSpan: ParseSourceSpan,
|
||||||
|
targetRefs: ElementOrDirectiveRef[]) {
|
||||||
|
if (identifier.indexOf('-') > -1) {
|
||||||
|
this._reportError(`"-" is not allowed in reference names`, sourceSpan);
|
||||||
|
}
|
||||||
|
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
|
||||||
|
}
|
||||||
|
|
||||||
private _parseProperty(name: string, expression: string, sourceSpan: ParseSourceSpan,
|
private _parseProperty(name: string, expression: string, sourceSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][],
|
targetMatchableAttrs: string[][],
|
||||||
targetProps: BoundElementOrDirectiveProperty[]) {
|
targetProps: BoundElementOrDirectiveProperty[]) {
|
||||||
|
@ -547,33 +592,28 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
|
|
||||||
private _parseDirectives(selectorMatcher: SelectorMatcher,
|
private _parseDirectives(selectorMatcher: SelectorMatcher,
|
||||||
elementCssSelector: CssSelector): CompileDirectiveMetadata[] {
|
elementCssSelector: CssSelector): CompileDirectiveMetadata[] {
|
||||||
var directives = [];
|
|
||||||
selectorMatcher.match(elementCssSelector,
|
|
||||||
(selector, directive) => { directives.push(directive); });
|
|
||||||
// Need to sort the directives so that we get consistent results throughout,
|
// Need to sort the directives so that we get consistent results throughout,
|
||||||
// as selectorMatcher uses Maps inside.
|
// as selectorMatcher uses Maps inside.
|
||||||
// Also need to make components the first directive in the array
|
// Also dedupe directives as they might match more than one time!
|
||||||
ListWrapper.sort(directives,
|
var directives = ListWrapper.createFixedSize(this.directivesIndex.size);
|
||||||
(dir1: CompileDirectiveMetadata, dir2: CompileDirectiveMetadata) => {
|
selectorMatcher.match(elementCssSelector, (selector, directive) => {
|
||||||
var dir1Comp = dir1.isComponent;
|
directives[this.directivesIndex.get(directive)] = directive;
|
||||||
var dir2Comp = dir2.isComponent;
|
});
|
||||||
if (dir1Comp && !dir2Comp) {
|
return directives.filter(dir => isPresent(dir));
|
||||||
return -1;
|
|
||||||
} else if (!dir1Comp && dir2Comp) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return this.directivesIndex.get(dir1) - this.directivesIndex.get(dir2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return directives;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createDirectiveAsts(elementName: string, directives: CompileDirectiveMetadata[],
|
private _createDirectiveAsts(isTemplateElement: boolean, elementName: string,
|
||||||
|
directives: CompileDirectiveMetadata[],
|
||||||
props: BoundElementOrDirectiveProperty[],
|
props: BoundElementOrDirectiveProperty[],
|
||||||
possibleExportAsVars: VariableAst[],
|
elementOrDirectiveRefs: ElementOrDirectiveRef[],
|
||||||
sourceSpan: ParseSourceSpan): DirectiveAst[] {
|
sourceSpan: ParseSourceSpan,
|
||||||
var matchedVariables = new Set<string>();
|
targetReferences: ReferenceAst[]): DirectiveAst[] {
|
||||||
|
var matchedReferences = new Set<string>();
|
||||||
|
var component: CompileDirectiveMetadata = null;
|
||||||
var directiveAsts = directives.map((directive: CompileDirectiveMetadata) => {
|
var directiveAsts = directives.map((directive: CompileDirectiveMetadata) => {
|
||||||
|
if (directive.isComponent) {
|
||||||
|
component = directive;
|
||||||
|
}
|
||||||
var hostProperties: BoundElementPropertyAst[] = [];
|
var hostProperties: BoundElementPropertyAst[] = [];
|
||||||
var hostEvents: BoundEventAst[] = [];
|
var hostEvents: BoundEventAst[] = [];
|
||||||
var directiveProperties: BoundDirectivePropertyAst[] = [];
|
var directiveProperties: BoundDirectivePropertyAst[] = [];
|
||||||
|
@ -581,21 +621,29 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
hostProperties);
|
hostProperties);
|
||||||
this._createDirectiveHostEventAsts(directive.hostListeners, sourceSpan, hostEvents);
|
this._createDirectiveHostEventAsts(directive.hostListeners, sourceSpan, hostEvents);
|
||||||
this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties);
|
this._createDirectivePropertyAsts(directive.inputs, props, directiveProperties);
|
||||||
var exportAsVars = [];
|
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
||||||
possibleExportAsVars.forEach((varAst) => {
|
if ((elOrDirRef.value.length === 0 && directive.isComponent) ||
|
||||||
if ((varAst.value.length === 0 && directive.isComponent) ||
|
(directive.exportAs == elOrDirRef.value)) {
|
||||||
(directive.exportAs == varAst.value)) {
|
targetReferences.push(new ReferenceAst(elOrDirRef.name, identifierToken(directive.type),
|
||||||
exportAsVars.push(varAst);
|
elOrDirRef.sourceSpan));
|
||||||
matchedVariables.add(varAst.name);
|
matchedReferences.add(elOrDirRef.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents,
|
return new DirectiveAst(directive, directiveProperties, hostProperties, hostEvents,
|
||||||
exportAsVars, sourceSpan);
|
sourceSpan);
|
||||||
});
|
});
|
||||||
possibleExportAsVars.forEach((varAst) => {
|
elementOrDirectiveRefs.forEach((elOrDirRef) => {
|
||||||
if (varAst.value.length > 0 && !SetWrapper.has(matchedVariables, varAst.name)) {
|
if (elOrDirRef.value.length > 0) {
|
||||||
this._reportError(`There is no directive with "exportAs" set to "${varAst.value}"`,
|
if (!SetWrapper.has(matchedReferences, elOrDirRef.name)) {
|
||||||
varAst.sourceSpan);
|
this._reportError(`There is no directive with "exportAs" set to "${elOrDirRef.value}"`,
|
||||||
|
elOrDirRef.sourceSpan);
|
||||||
|
};
|
||||||
|
} else if (isBlank(component)) {
|
||||||
|
var refToken = null;
|
||||||
|
if (isTemplateElement) {
|
||||||
|
refToken = identifierToken(Identifiers.TemplateRef);
|
||||||
|
}
|
||||||
|
targetReferences.push(new ReferenceAst(elOrDirRef.name, refToken, elOrDirRef.sourceSpan));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return directiveAsts;
|
return directiveAsts;
|
||||||
|
@ -793,6 +841,10 @@ class BoundElementOrDirectiveProperty {
|
||||||
public sourceSpan: ParseSourceSpan) {}
|
public sourceSpan: ParseSourceSpan) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ElementOrDirectiveRef {
|
||||||
|
constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {}
|
||||||
|
}
|
||||||
|
|
||||||
export function splitClasses(classAttrValue: string): string[] {
|
export function splitClasses(classAttrValue: string): string[] {
|
||||||
return StringWrapper.split(classAttrValue.trim(), /\s+/g);
|
return StringWrapper.split(classAttrValue.trim(), /\s+/g);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {InjectMethodVars} from './constants';
|
||||||
import {CompileView} from './compile_view';
|
import {CompileView} from './compile_view';
|
||||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {TemplateAst, ProviderAst, ProviderAstType} from '../template_ast';
|
import {TemplateAst, ProviderAst, ProviderAstType, ReferenceAst} from '../template_ast';
|
||||||
import {
|
import {
|
||||||
CompileTokenMap,
|
CompileTokenMap,
|
||||||
CompileDirectiveMetadata,
|
CompileDirectiveMetadata,
|
||||||
|
@ -13,7 +13,7 @@ import {
|
||||||
CompileProviderMetadata,
|
CompileProviderMetadata,
|
||||||
CompileDiDependencyMetadata,
|
CompileDiDependencyMetadata,
|
||||||
CompileIdentifierMetadata,
|
CompileIdentifierMetadata,
|
||||||
CompileTypeMetadata
|
CompileTypeMetadata,
|
||||||
} from '../compile_metadata';
|
} from '../compile_metadata';
|
||||||
import {getPropertyInView, createDiTokenExpression, injectFromViewParentInjector} from './util';
|
import {getPropertyInView, createDiTokenExpression, injectFromViewParentInjector} from './util';
|
||||||
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
|
import {CompileQuery, createQueryList, addQueryToTokenMap} from './compile_query';
|
||||||
|
@ -30,7 +30,7 @@ export class CompileNode {
|
||||||
|
|
||||||
export class CompileElement extends CompileNode {
|
export class CompileElement extends CompileNode {
|
||||||
static createNull(): CompileElement {
|
static createNull(): CompileElement {
|
||||||
return new CompileElement(null, null, null, null, null, null, [], [], false, false, {});
|
return new CompileElement(null, null, null, null, null, null, [], [], false, false, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compViewExpr: o.Expression = null;
|
private _compViewExpr: o.Expression = null;
|
||||||
|
@ -47,15 +47,18 @@ export class CompileElement extends CompileNode {
|
||||||
public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
|
public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
|
||||||
public embeddedView: CompileView;
|
public embeddedView: CompileView;
|
||||||
public directiveInstances: o.Expression[];
|
public directiveInstances: o.Expression[];
|
||||||
|
public referenceTokens: {[key: string]: CompileTokenMetadata};
|
||||||
|
|
||||||
constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
|
constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
|
||||||
renderNode: o.Expression, sourceAst: TemplateAst,
|
renderNode: o.Expression, sourceAst: TemplateAst,
|
||||||
public component: CompileDirectiveMetadata,
|
public component: CompileDirectiveMetadata,
|
||||||
private _directives: CompileDirectiveMetadata[],
|
private _directives: CompileDirectiveMetadata[],
|
||||||
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
|
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
|
||||||
public hasEmbeddedView: boolean,
|
public hasEmbeddedView: boolean, references: ReferenceAst[]) {
|
||||||
public variableTokens: {[key: string]: CompileTokenMetadata}) {
|
|
||||||
super(parent, view, nodeIndex, renderNode, sourceAst);
|
super(parent, view, nodeIndex, renderNode, sourceAst);
|
||||||
|
this.referenceTokens = {};
|
||||||
|
references.forEach(ref => this.referenceTokens[ref.name] = ref.value);
|
||||||
|
|
||||||
this.elementRef = o.importExpr(Identifiers.ElementRef).instantiate([this.renderNode]);
|
this.elementRef = o.importExpr(Identifiers.ElementRef).instantiate([this.renderNode]);
|
||||||
this._instances.add(identifierToken(Identifiers.ElementRef), this.elementRef);
|
this._instances.add(identifierToken(Identifiers.ElementRef), this.elementRef);
|
||||||
this.injector = o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]);
|
this.injector = o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]);
|
||||||
|
@ -167,15 +170,15 @@ export class CompileElement extends CompileNode {
|
||||||
queriesWithReads,
|
queriesWithReads,
|
||||||
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
|
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
|
||||||
});
|
});
|
||||||
StringMapWrapper.forEach(this.variableTokens, (_, varName) => {
|
StringMapWrapper.forEach(this.referenceTokens, (_, varName) => {
|
||||||
var token = this.variableTokens[varName];
|
var token = this.referenceTokens[varName];
|
||||||
var varValue;
|
var varValue;
|
||||||
if (isPresent(token)) {
|
if (isPresent(token)) {
|
||||||
varValue = this._instances.get(token);
|
varValue = this._instances.get(token);
|
||||||
} else {
|
} else {
|
||||||
varValue = this.renderNode;
|
varValue = this.renderNode;
|
||||||
}
|
}
|
||||||
this.view.variables.set(varName, varValue);
|
this.view.locals.set(varName, varValue);
|
||||||
var varToken = new CompileTokenMetadata({value: varName});
|
var varToken = new CompileTokenMetadata({value: varName});
|
||||||
ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
|
ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
|
||||||
.map(query => new _QueryWithRead(query, varToken)));
|
.map(query => new _QueryWithRead(query, varToken)));
|
||||||
|
@ -186,8 +189,8 @@ export class CompileElement extends CompileNode {
|
||||||
// query for an identifier
|
// query for an identifier
|
||||||
value = this._instances.get(queryWithRead.read);
|
value = this._instances.get(queryWithRead.read);
|
||||||
} else {
|
} else {
|
||||||
// query for a variable
|
// query for a reference
|
||||||
var token = this.variableTokens[queryWithRead.read.value];
|
var token = this.referenceTokens[queryWithRead.read.value];
|
||||||
if (isPresent(token)) {
|
if (isPresent(token)) {
|
||||||
value = this._instances.get(token);
|
value = this._instances.get(token);
|
||||||
} else {
|
} else {
|
||||||
|
@ -247,12 +250,6 @@ export class CompileElement extends CompileNode {
|
||||||
(resolvedProvider) => createDiTokenExpression(resolvedProvider.token));
|
(resolvedProvider) => createDiTokenExpression(resolvedProvider.token));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeclaredVariablesNames(): string[] {
|
|
||||||
var res = [];
|
|
||||||
StringMapWrapper.forEach(this.variableTokens, (_, key) => { res.push(key); });
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
|
private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
|
||||||
var result: CompileQuery[] = [];
|
var result: CompileQuery[] = [];
|
||||||
var currentEl: CompileElement = this;
|
var currentEl: CompileElement = this;
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class CompileView implements NameResolver {
|
||||||
public componentView: CompileView;
|
public componentView: CompileView;
|
||||||
public purePipes = new Map<string, CompilePipe>();
|
public purePipes = new Map<string, CompilePipe>();
|
||||||
public pipes: CompilePipe[] = [];
|
public pipes: CompilePipe[] = [];
|
||||||
public variables = new Map<string, o.Expression>();
|
public locals = new Map<string, o.Expression>();
|
||||||
public className: string;
|
public className: string;
|
||||||
public classType: o.Type;
|
public classType: o.Type;
|
||||||
public viewFactory: o.ReadVarExpr;
|
public viewFactory: o.ReadVarExpr;
|
||||||
|
@ -112,7 +112,7 @@ export class CompileView implements NameResolver {
|
||||||
}
|
}
|
||||||
this.viewQueries = viewQueries;
|
this.viewQueries = viewQueries;
|
||||||
templateVariableBindings.forEach((entry) => {
|
templateVariableBindings.forEach((entry) => {
|
||||||
this.variables.set(entry[1], o.THIS_EXPR.prop('locals').key(o.literal(entry[0])));
|
this.locals.set(entry[1], o.THIS_EXPR.prop('locals').key(o.literal(entry[0])));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.declarationElement.isNull()) {
|
if (!this.declarationElement.isNull()) {
|
||||||
|
@ -133,15 +133,15 @@ export class CompileView implements NameResolver {
|
||||||
return pipe.call(this, [input].concat(args));
|
return pipe.call(this, [input].concat(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
getVariable(name: string): o.Expression {
|
getLocal(name: string): o.Expression {
|
||||||
if (name == EventHandlerVars.event.name) {
|
if (name == EventHandlerVars.event.name) {
|
||||||
return EventHandlerVars.event;
|
return EventHandlerVars.event;
|
||||||
}
|
}
|
||||||
var currView: CompileView = this;
|
var currView: CompileView = this;
|
||||||
var result = currView.variables.get(name);
|
var result = currView.locals.get(name);
|
||||||
while (isBlank(result) && isPresent(currView.declarationElement.view)) {
|
while (isBlank(result) && isPresent(currView.declarationElement.view)) {
|
||||||
currView = currView.declarationElement.view;
|
currView = currView.declarationElement.view;
|
||||||
result = currView.variables.get(name);
|
result = currView.locals.get(name);
|
||||||
}
|
}
|
||||||
if (isPresent(result)) {
|
if (isPresent(result)) {
|
||||||
return getPropertyInView(result, this, currView);
|
return getPropertyInView(result, this, currView);
|
||||||
|
|
|
@ -9,7 +9,7 @@ var IMPLICIT_RECEIVER = o.variable('#implicit');
|
||||||
|
|
||||||
export interface NameResolver {
|
export interface NameResolver {
|
||||||
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
|
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
|
||||||
getVariable(name: string): o.Expression;
|
getLocal(name: string): o.Expression;
|
||||||
createLiteralArray(values: o.Expression[]): o.Expression;
|
createLiteralArray(values: o.Expression[]): o.Expression;
|
||||||
createLiteralMap(values: Array<Array<string | o.Expression>>): o.Expression;
|
createLiteralMap(values: Array<Array<string | o.Expression>>): o.Expression;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||||
var result = null;
|
var result = null;
|
||||||
var receiver = ast.receiver.visit(this, _Mode.Expression);
|
var receiver = ast.receiver.visit(this, _Mode.Expression);
|
||||||
if (receiver === IMPLICIT_RECEIVER) {
|
if (receiver === IMPLICIT_RECEIVER) {
|
||||||
var varExpr = this._nameResolver.getVariable(ast.name);
|
var varExpr = this._nameResolver.getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (isPresent(varExpr)) {
|
||||||
result = varExpr.callFn(args);
|
result = varExpr.callFn(args);
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,7 +204,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||||
var result = null;
|
var result = null;
|
||||||
var receiver = ast.receiver.visit(this, _Mode.Expression);
|
var receiver = ast.receiver.visit(this, _Mode.Expression);
|
||||||
if (receiver === IMPLICIT_RECEIVER) {
|
if (receiver === IMPLICIT_RECEIVER) {
|
||||||
result = this._nameResolver.getVariable(ast.name);
|
result = this._nameResolver.getLocal(ast.name);
|
||||||
if (isBlank(result)) {
|
if (isBlank(result)) {
|
||||||
receiver = this._implicitReceiver;
|
receiver = this._implicitReceiver;
|
||||||
}
|
}
|
||||||
|
@ -217,9 +217,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||||
visitPropertyWrite(ast: cdAst.PropertyWrite, mode: _Mode): any {
|
visitPropertyWrite(ast: cdAst.PropertyWrite, mode: _Mode): any {
|
||||||
var receiver: o.Expression = ast.receiver.visit(this, _Mode.Expression);
|
var receiver: o.Expression = ast.receiver.visit(this, _Mode.Expression);
|
||||||
if (receiver === IMPLICIT_RECEIVER) {
|
if (receiver === IMPLICIT_RECEIVER) {
|
||||||
var varExpr = this._nameResolver.getVariable(ast.name);
|
var varExpr = this._nameResolver.getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (isPresent(varExpr)) {
|
||||||
throw new BaseException('Cannot reassign a variable binding');
|
throw new BaseException('Cannot assign to a reference or variable!');
|
||||||
}
|
}
|
||||||
receiver = this._implicitReceiver;
|
receiver = this._implicitReceiver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
NgContentAst,
|
NgContentAst,
|
||||||
EmbeddedTemplateAst,
|
EmbeddedTemplateAst,
|
||||||
ElementAst,
|
ElementAst,
|
||||||
|
ReferenceAst,
|
||||||
VariableAst,
|
VariableAst,
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
|
@ -113,6 +114,7 @@ class ViewBinderVisitor implements TemplateAstVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
|
||||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {
|
||||||
NgContentAst,
|
NgContentAst,
|
||||||
EmbeddedTemplateAst,
|
EmbeddedTemplateAst,
|
||||||
ElementAst,
|
ElementAst,
|
||||||
|
ReferenceAst,
|
||||||
VariableAst,
|
VariableAst,
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
|
@ -201,8 +202,6 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
|
|
||||||
var component = ast.getComponent();
|
var component = ast.getComponent();
|
||||||
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
||||||
var variables =
|
|
||||||
_readHtmlAndDirectiveVariables(ast.exportAsVars, ast.directives, this.view.viewType);
|
|
||||||
var htmlAttrs = _readHtmlAttrs(ast.attrs);
|
var htmlAttrs = _readHtmlAttrs(ast.attrs);
|
||||||
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
|
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
|
||||||
for (var i = 0; i < attrNameAndValues.length; i++) {
|
for (var i = 0; i < attrNameAndValues.length; i++) {
|
||||||
|
@ -216,7 +215,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
}
|
}
|
||||||
var compileElement =
|
var compileElement =
|
||||||
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
|
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
|
||||||
ast.providers, ast.hasViewContainer, false, variables);
|
ast.providers, ast.hasViewContainer, false, ast.references);
|
||||||
this.view.nodes.push(compileElement);
|
this.view.nodes.push(compileElement);
|
||||||
var compViewExpr: o.ReadVarExpr = null;
|
var compViewExpr: o.ReadVarExpr = null;
|
||||||
if (isPresent(component)) {
|
if (isPresent(component)) {
|
||||||
|
@ -269,13 +268,13 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
.toStmt());
|
.toStmt());
|
||||||
var renderNode = o.THIS_EXPR.prop(fieldName);
|
var renderNode = o.THIS_EXPR.prop(fieldName);
|
||||||
|
|
||||||
var templateVariableBindings = ast.vars.map(
|
var templateVariableBindings = ast.variables.map(
|
||||||
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
|
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
|
||||||
|
|
||||||
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
||||||
var compileElement =
|
var compileElement =
|
||||||
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
|
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
|
||||||
ast.providers, ast.hasViewContainer, true, {});
|
ast.providers, ast.hasViewContainer, true, ast.references);
|
||||||
this.view.nodes.push(compileElement);
|
this.view.nodes.push(compileElement);
|
||||||
|
|
||||||
this.nestedViewCount++;
|
this.nestedViewCount++;
|
||||||
|
@ -297,6 +296,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitReference(ast: ReferenceAst, ctx: any): any { return null; }
|
||||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||||
|
@ -321,24 +321,6 @@ function _readHtmlAttrs(attrs: AttrAst[]): {[key: string]: string} {
|
||||||
return htmlAttrs;
|
return htmlAttrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _readHtmlAndDirectiveVariables(elementExportAsVars: VariableAst[],
|
|
||||||
directives: DirectiveAst[],
|
|
||||||
viewType: ViewType): {[key: string]: CompileTokenMetadata} {
|
|
||||||
var variables: {[key: string]: CompileTokenMetadata} = {};
|
|
||||||
var component: CompileDirectiveMetadata = null;
|
|
||||||
directives.forEach((directive) => {
|
|
||||||
if (directive.directive.isComponent) {
|
|
||||||
component = directive.directive;
|
|
||||||
}
|
|
||||||
directive.exportAsVars.forEach(
|
|
||||||
varAst => { variables[varAst.name] = identifierToken(directive.directive.type); });
|
|
||||||
});
|
|
||||||
elementExportAsVars.forEach((varAst) => {
|
|
||||||
variables[varAst.name] = isPresent(component) ? identifierToken(component.type) : null;
|
|
||||||
});
|
|
||||||
return variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
||||||
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
|
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
|
||||||
return `${attrValue1} ${attrValue2}`;
|
return `${attrValue1} ${attrValue2}`;
|
||||||
|
@ -392,7 +374,7 @@ function createStaticNodeDebugInfo(node: CompileNode): o.Expression {
|
||||||
if (isPresent(compileElement.component)) {
|
if (isPresent(compileElement.component)) {
|
||||||
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
|
componentToken = createDiTokenExpression(identifierToken(compileElement.component.type));
|
||||||
}
|
}
|
||||||
StringMapWrapper.forEach(compileElement.variableTokens, (token, varName) => {
|
StringMapWrapper.forEach(compileElement.referenceTokens, (token, varName) => {
|
||||||
varTokenEntries.push(
|
varTokenEntries.push(
|
||||||
[varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
|
[varName, isPresent(token) ? createDiTokenExpression(token) : o.NULL_EXPR]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,7 +70,7 @@ export abstract class ChangeDetectorRef {
|
||||||
* @Component({
|
* @Component({
|
||||||
* selector: 'giant-list',
|
* selector: 'giant-list',
|
||||||
* template: `
|
* template: `
|
||||||
* <li *ngFor="#d of dataProvider.data">Data {{d}}</lig>
|
* <li *ngFor="let d of dataProvider.data">Data {{d}}</lig>
|
||||||
* `,
|
* `,
|
||||||
* directives: [NgFor]
|
* directives: [NgFor]
|
||||||
* })
|
* })
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
import {print} from 'angular2/src/facade/lang';
|
import {print, warn} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
|
// Note: Need to rename warn as in Dart
|
||||||
|
// class members and imports can't use the same name.
|
||||||
|
let _warnImpl = warn;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Console {
|
export class Console {
|
||||||
log(message: string): void { print(message); }
|
log(message: string): void { print(message); }
|
||||||
}
|
// Note: for reporting errors use `DOM.logError()` as it is platform specific
|
||||||
|
warn(message: string): void { _warnImpl(message); }
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {ViewType} from './view_type';
|
||||||
@CONST()
|
@CONST()
|
||||||
export class StaticNodeDebugInfo {
|
export class StaticNodeDebugInfo {
|
||||||
constructor(public providerTokens: any[], public componentToken: any,
|
constructor(public providerTokens: any[], public componentToken: any,
|
||||||
public varTokens: {[key: string]: any}) {}
|
public refTokens: {[key: string]: any}) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DebugContext implements RenderDebugInfo {
|
export class DebugContext implements RenderDebugInfo {
|
||||||
|
@ -61,15 +61,15 @@ export class DebugContext implements RenderDebugInfo {
|
||||||
ListWrapper.forEachWithIndex(
|
ListWrapper.forEachWithIndex(
|
||||||
this._view.staticNodeDebugInfos,
|
this._view.staticNodeDebugInfos,
|
||||||
(staticNodeInfo: StaticNodeDebugInfo, nodeIndex: number) => {
|
(staticNodeInfo: StaticNodeDebugInfo, nodeIndex: number) => {
|
||||||
var vars = staticNodeInfo.varTokens;
|
var refs = staticNodeInfo.refTokens;
|
||||||
StringMapWrapper.forEach(vars, (varToken, varName) => {
|
StringMapWrapper.forEach(refs, (refToken, refName) => {
|
||||||
var varValue;
|
var varValue;
|
||||||
if (isBlank(varToken)) {
|
if (isBlank(refToken)) {
|
||||||
varValue = isPresent(this._view.allNodes) ? this._view.allNodes[nodeIndex] : null;
|
varValue = isPresent(this._view.allNodes) ? this._view.allNodes[nodeIndex] : null;
|
||||||
} else {
|
} else {
|
||||||
varValue = this._view.injectorGet(varToken, nodeIndex, null);
|
varValue = this._view.injectorGet(refToken, nodeIndex, null);
|
||||||
}
|
}
|
||||||
varValues[varName] = varValue;
|
varValues[refName] = varValue;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
StringMapWrapper.forEach(this._view.locals,
|
StringMapWrapper.forEach(this._view.locals,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||||
*
|
*
|
||||||
* Implements an iterable interface, therefore it can be used in both ES6
|
* Implements an iterable interface, therefore it can be used in both ES6
|
||||||
* javascript `for (var i of items)` loops as well as in Angular templates with
|
* javascript `for (var i of items)` loops as well as in Angular templates with
|
||||||
* `*ngFor="#i of myList"`.
|
* `*ngFor="let i of myList"`.
|
||||||
*
|
*
|
||||||
* Changes can be observed by subscribing to the changes `Observable`.
|
* Changes can be observed by subscribing to the changes `Observable`.
|
||||||
*
|
*
|
||||||
|
|
|
@ -34,7 +34,7 @@ export abstract class ViewRef extends ChangeDetectorRef {
|
||||||
* ```
|
* ```
|
||||||
* Count: {{items.length}}
|
* Count: {{items.length}}
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="var item of items">{{item}}</li>
|
* <li *ngFor="let item of items">{{item}}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
@ -44,7 +44,7 @@ export abstract class ViewRef extends ChangeDetectorRef {
|
||||||
* ```
|
* ```
|
||||||
* Count: {{items.length}}
|
* Count: {{items.length}}
|
||||||
* <ul>
|
* <ul>
|
||||||
* <template ngFor var-item [ngForOf]="items"></template>
|
* <template ngFor let-item [ngForOf]="items"></template>
|
||||||
* </ul>
|
* </ul>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
|
|
@ -964,7 +964,7 @@ export var Attribute: AttributeMetadataFactory = makeParamDecorator(AttributeMet
|
||||||
* ```html
|
* ```html
|
||||||
* <tabs>
|
* <tabs>
|
||||||
* <pane title="Overview">...</pane>
|
* <pane title="Overview">...</pane>
|
||||||
* <pane *ngFor="#o of objects" [title]="o.title">{{o.text}}</pane>
|
* <pane *ngFor="let o of objects" [title]="o.title">{{o.text}}</pane>
|
||||||
* </tabs>
|
* </tabs>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
@ -983,7 +983,7 @@ export var Attribute: AttributeMetadataFactory = makeParamDecorator(AttributeMet
|
||||||
* selector: 'tabs',
|
* selector: 'tabs',
|
||||||
* template: `
|
* template: `
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#pane of panes">{{pane.title}}</li>
|
* <li *ngFor="let pane of panes">{{pane.title}}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <ng-content></ng-content>
|
* <ng-content></ng-content>
|
||||||
* `
|
* `
|
||||||
|
|
|
@ -46,7 +46,7 @@ export class AttributeMetadata extends DependencyMetadata {
|
||||||
* ```html
|
* ```html
|
||||||
* <tabs>
|
* <tabs>
|
||||||
* <pane title="Overview">...</pane>
|
* <pane title="Overview">...</pane>
|
||||||
* <pane *ngFor="#o of objects" [title]="o.title">{{o.text}}</pane>
|
* <pane *ngFor="let o of objects" [title]="o.title">{{o.text}}</pane>
|
||||||
* </tabs>
|
* </tabs>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
@ -65,7 +65,7 @@ export class AttributeMetadata extends DependencyMetadata {
|
||||||
* selector: 'tabs',
|
* selector: 'tabs',
|
||||||
* template: `
|
* template: `
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#pane of panes">{{pane.title}}</li>
|
* <li *ngFor="let pane of panes">{{pane.title}}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <ng-content></ng-content>
|
* <ng-content></ng-content>
|
||||||
* `
|
* `
|
||||||
|
|
|
@ -149,7 +149,7 @@ export interface OnInit { ngOnInit(); }
|
||||||
* template: `
|
* template: `
|
||||||
* <p>Changes:</p>
|
* <p>Changes:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#line of logs">{{line}}</li>
|
* <li *ngFor="let line of logs">{{line}}</li>
|
||||||
* </ul>`,
|
* </ul>`,
|
||||||
* directives: [NgFor]
|
* directives: [NgFor]
|
||||||
* })
|
* })
|
||||||
|
|
|
@ -104,7 +104,7 @@ export class ViewMetadata {
|
||||||
* directives: [NgFor]
|
* directives: [NgFor]
|
||||||
* template: '
|
* template: '
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li *ngFor="#item of items">{{item}}</li>
|
* <li *ngFor="let item of items">{{item}}</li>
|
||||||
* </ul>'
|
* </ul>'
|
||||||
* })
|
* })
|
||||||
* class MyComponent {
|
* class MyComponent {
|
||||||
|
|
|
@ -298,6 +298,10 @@ bool isJsObject(o) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn(o) {
|
||||||
|
print(o);
|
||||||
|
}
|
||||||
|
|
||||||
// Functions below are noop in Dart. Imperatively controlling dev mode kills
|
// Functions below are noop in Dart. Imperatively controlling dev mode kills
|
||||||
// tree shaking. We should only rely on `assertionsEnabled`.
|
// tree shaking. We should only rely on `assertionsEnabled`.
|
||||||
@Deprecated('Do not use this function. It is for JS only. There is no alternative.')
|
@Deprecated('Do not use this function. It is for JS only. There is no alternative.')
|
||||||
|
|
|
@ -408,6 +408,10 @@ export function print(obj: Error | Object) {
|
||||||
console.log(obj);
|
console.log(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function warn(obj: Error | Object) {
|
||||||
|
console.warn(obj);
|
||||||
|
}
|
||||||
|
|
||||||
// Can't be all uppercase as our transpiler would think it is a special directive...
|
// Can't be all uppercase as our transpiler would think it is a special directive...
|
||||||
export class Json {
|
export class Json {
|
||||||
static parse(s: string): Object { return _global.JSON.parse(s); }
|
static parse(s: string): Object { return _global.JSON.parse(s); }
|
||||||
|
|
|
@ -185,11 +185,13 @@ export class RouterLinkTransform implements TemplateAstVisitor {
|
||||||
let updatedChildren = ast.children.map(c => c.visit(this, context));
|
let updatedChildren = ast.children.map(c => c.visit(this, context));
|
||||||
let updatedInputs = ast.inputs.map(c => c.visit(this, context));
|
let updatedInputs = ast.inputs.map(c => c.visit(this, context));
|
||||||
let updatedDirectives = ast.directives.map(c => c.visit(this, context));
|
let updatedDirectives = ast.directives.map(c => c.visit(this, context));
|
||||||
return new ElementAst(ast.name, ast.attrs, updatedInputs, ast.outputs, ast.exportAsVars,
|
return new ElementAst(ast.name, ast.attrs, updatedInputs, ast.outputs, ast.references,
|
||||||
updatedDirectives, ast.providers, ast.hasViewContainer, updatedChildren,
|
updatedDirectives, ast.providers, ast.hasViewContainer, updatedChildren,
|
||||||
ast.ngContentIndex, ast.sourceSpan);
|
ast.ngContentIndex, ast.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitReference(ast: any, context: any): any { return ast; }
|
||||||
|
|
||||||
visitVariable(ast: any, context: any): any { return ast; }
|
visitVariable(ast: any, context: any): any { return ast; }
|
||||||
|
|
||||||
visitEvent(ast: any, context: any): any { return ast; }
|
visitEvent(ast: any, context: any): any { return ast; }
|
||||||
|
@ -205,7 +207,7 @@ export class RouterLinkTransform implements TemplateAstVisitor {
|
||||||
visitDirective(ast: DirectiveAst, context: any): any {
|
visitDirective(ast: DirectiveAst, context: any): any {
|
||||||
let updatedInputs = ast.inputs.map(c => c.visit(this, context));
|
let updatedInputs = ast.inputs.map(c => c.visit(this, context));
|
||||||
return new DirectiveAst(ast.directive, updatedInputs, ast.hostProperties, ast.hostEvents,
|
return new DirectiveAst(ast.directive, updatedInputs, ast.hostProperties, ast.hostEvents,
|
||||||
ast.exportAsVars, ast.sourceSpan);
|
ast.sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
|
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function main() {
|
||||||
|
|
||||||
it('should clean up when the directive is destroyed',
|
it('should clean up when the directive is destroyed',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {By} from 'angular2/platform/common_dom';
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('ngFor', () => {
|
describe('ngFor', () => {
|
||||||
var TEMPLATE =
|
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',
|
it('should reflect initial elements',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
@ -100,7 +100,7 @@ export function main() {
|
||||||
|
|
||||||
it('should iterate over an array of objects',
|
it('should iterate over an array of objects',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -130,7 +130,7 @@ export function main() {
|
||||||
|
|
||||||
it('should gracefully handle nulls',
|
it('should gracefully handle nulls',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
@ -207,8 +207,8 @@ export function main() {
|
||||||
it('should repeat over nested arrays',
|
it('should repeat over nested arrays',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<div>' +
|
var template = '<div>' +
|
||||||
'<div template="ngFor #item of items">' +
|
'<div template="ngFor let item of items">' +
|
||||||
'<div template="ngFor #subitem of item">' +
|
'<div template="ngFor let subitem of item">' +
|
||||||
'{{subitem}}-{{item.length}};' +
|
'{{subitem}}-{{item.length}};' +
|
||||||
'</div>|' +
|
'</div>|' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
@ -233,8 +233,8 @@ export function main() {
|
||||||
|
|
||||||
it('should repeat over nested arrays with no intermediate element',
|
it('should repeat over nested arrays with no intermediate element',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<div><template ngFor #item [ngForOf]="items">' +
|
var template = '<div><template ngFor let-item [ngForOf]="items">' +
|
||||||
'<div template="ngFor #subitem of item">' +
|
'<div template="ngFor let subitem of item">' +
|
||||||
'{{subitem}}-{{item.length}};' +
|
'{{subitem}}-{{item.length}};' +
|
||||||
'</div></template></div>';
|
'</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',
|
it('should repeat over nested ngIf that are the last node in the ngFor temlate',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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>`;
|
`<div *ngIf="i % 2 == 0">even|</div></template></div>`;
|
||||||
|
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
@ -282,7 +282,7 @@ export function main() {
|
||||||
it('should display indices correctly',
|
it('should display indices correctly',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -301,7 +301,7 @@ export function main() {
|
||||||
it('should display first item correctly',
|
it('should display first item correctly',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -320,7 +320,7 @@ export function main() {
|
||||||
it('should display last item correctly',
|
it('should display last item correctly',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -339,7 +339,7 @@ export function main() {
|
||||||
it('should display even items correctly',
|
it('should display even items correctly',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -358,7 +358,7 @@ export function main() {
|
||||||
it('should display odd items correctly',
|
it('should display odd items correctly',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
|
@ -381,7 +381,7 @@ export function main() {
|
||||||
'<ul><template ngFor [ngForOf]="items" [ngForTemplate]="contentTpl"></template></ul>')
|
'<ul><template ngFor [ngForOf]="items" [ngForTemplate]="contentTpl"></template></ul>')
|
||||||
.overrideTemplate(
|
.overrideTemplate(
|
||||||
ComponentUsingTestComponent,
|
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)
|
.createAsync(ComponentUsingTestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
var testComponent = fixture.debugElement.children[0];
|
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',
|
it('should use a default template if a custom one is null',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideTemplate(TestComponent, `<ul><template ngFor #item [ngForOf]="items"
|
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
|
||||||
[ngForTemplate]="contentTpl" #i="index">{{i}}: {{item}};</template></ul>`)
|
[ngForTemplate]="contentTpl" let-i="index">{{i}}: {{item}};</template></ul>`)
|
||||||
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
|
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
|
||||||
.createAsync(ComponentUsingTestComponent)
|
.createAsync(ComponentUsingTestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
@ -411,11 +411,11 @@ export function main() {
|
||||||
|
|
||||||
it('should use a custom template when both default and a custom one are present',
|
it('should use a custom template when both default and a custom one are present',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideTemplate(TestComponent, `<ul><template ngFor #item [ngForOf]="items"
|
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
|
||||||
[ngForTemplate]="contentTpl" #i="index">{{i}}=> {{item}};</template></ul>`)
|
[ngForTemplate]="contentTpl" let-i="index">{{i}}=> {{item}};</template></ul>`)
|
||||||
.overrideTemplate(
|
.overrideTemplate(
|
||||||
ComponentUsingTestComponent,
|
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)
|
.createAsync(ComponentUsingTestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
var testComponent = fixture.debugElement.children[0];
|
var testComponent = fixture.debugElement.children[0];
|
||||||
|
@ -431,7 +431,7 @@ export function main() {
|
||||||
it('should not replace tracked items',
|
it('should not replace tracked items',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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>
|
<p>{{items[i]}}</p>
|
||||||
</template>`;
|
</template>`;
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
@ -453,7 +453,7 @@ export function main() {
|
||||||
it('should update implicit local variable on view',
|
it('should update implicit local variable on view',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
@ -469,7 +469,7 @@ export function main() {
|
||||||
it('should move items around and keep them updated ',
|
it('should move items around and keep them updated ',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
@ -488,7 +488,7 @@ export function main() {
|
||||||
it('should handle added and removed items properly when tracking by index',
|
it('should handle added and removed items properly when tracking by index',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((fixture) => {
|
.then((fixture) => {
|
||||||
|
|
|
@ -448,7 +448,7 @@ export function main() {
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter],
|
inject([TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<select>
|
var t = `<select>
|
||||||
<option *ngFor="#city of list" [value]="city['id']">
|
<option *ngFor="let city of list" [value]="city['id']">
|
||||||
{{ city['name'] }}
|
{{ city['name'] }}
|
||||||
</option>
|
</option>
|
||||||
</select>`;
|
</select>`;
|
||||||
|
@ -503,7 +503,7 @@ export function main() {
|
||||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
var t = `<div [ngFormModel]="form">
|
var t = `<div [ngFormModel]="form">
|
||||||
<select ngControl="city">
|
<select ngControl="city">
|
||||||
<option *ngFor="#c of data" [value]="c"></option>
|
<option *ngFor="let c of data" [value]="c"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -528,7 +528,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<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>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -560,7 +560,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<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>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -588,7 +588,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<select [(ngModel)]="selectedCity">
|
||||||
<option *ngFor="#c of list" [ngValue]="c">{{c}}</option>
|
<option *ngFor="let c of list" [ngValue]="c">{{c}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((fixture) => {
|
tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((fixture) => {
|
||||||
|
@ -614,7 +614,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<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>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<select [(ngModel)]="selectedCity">
|
||||||
<option *ngFor="#c of list" [ngValue]="c">{{c}}</option>
|
<option *ngFor="let c of list" [ngValue]="c">{{c}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ export function main() {
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
var t = `<div>
|
var t = `<div>
|
||||||
<select [(ngModel)]="selectedCity">
|
<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>
|
</select>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTemplateBindings(text, location = null): any {
|
function parseTemplateBindings(text, location = null): any {
|
||||||
return createParser().parseTemplateBindings(text, location);
|
return createParser().parseTemplateBindings(text, location).templateBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseInterpolation(text, location = null): any {
|
function parseInterpolation(text, location = null): any {
|
||||||
|
@ -293,7 +293,7 @@ export function main() {
|
||||||
function keyValues(templateBindings: any[]) {
|
function keyValues(templateBindings: any[]) {
|
||||||
return templateBindings.map(binding => {
|
return templateBindings.map(binding => {
|
||||||
if (binding.keyIsVar) {
|
if (binding.keyIsVar) {
|
||||||
return '#' + binding.key + (isBlank(binding.name) ? '=null' : '=' + binding.name);
|
return 'let ' + binding.key + (isBlank(binding.name) ? '=null' : '=' + binding.name);
|
||||||
} else {
|
} else {
|
||||||
return binding.key + (isBlank(binding.expression) ? '' : `=${binding.expression}`)
|
return binding.key + (isBlank(binding.expression) ? '' : `=${binding.expression}`)
|
||||||
}
|
}
|
||||||
|
@ -339,8 +339,8 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should detect names as value', () => {
|
it('should detect names as value', () => {
|
||||||
var bindings = parseTemplateBindings("a:#b");
|
var bindings = parseTemplateBindings("a:let b");
|
||||||
expect(keyValues(bindings)).toEqual(['a', '#b=\$implicit']);
|
expect(keyValues(bindings)).toEqual(['a', 'let b=\$implicit']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow space and colon as separators', () => {
|
it('should allow space and colon as separators', () => {
|
||||||
|
@ -370,31 +370,46 @@ export function main() {
|
||||||
expect(bindings[0].expression.location).toEqual('location');
|
expect(bindings[0].expression.location).toEqual('location');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support var/# notation', () => {
|
it('should support var notation with a deprecation warning', () => {
|
||||||
var bindings = parseTemplateBindings("var i");
|
var bindings = createParser().parseTemplateBindings("var i", null);
|
||||||
expect(keyValues(bindings)).toEqual(['#i=\$implicit']);
|
expect(keyValues(bindings.templateBindings)).toEqual(['let i=\$implicit']);
|
||||||
|
expect(bindings.warnings)
|
||||||
|
.toEqual(['"var" inside of expressions is deprecated. Use "let" instead!']);
|
||||||
|
});
|
||||||
|
|
||||||
bindings = parseTemplateBindings("#i");
|
it('should support # notation with a deprecation warning', () => {
|
||||||
expect(keyValues(bindings)).toEqual(['#i=\$implicit']);
|
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");
|
it('should support let notation', () => {
|
||||||
expect(keyValues(bindings)).toEqual(['#a=\$implicit', '#b=\$implicit']);
|
var bindings = parseTemplateBindings("let i");
|
||||||
|
expect(keyValues(bindings)).toEqual(['let i=\$implicit']);
|
||||||
|
|
||||||
bindings = parseTemplateBindings("#a; #b;");
|
bindings = parseTemplateBindings("let i");
|
||||||
expect(keyValues(bindings)).toEqual(['#a=\$implicit', '#b=\$implicit']);
|
expect(keyValues(bindings)).toEqual(['let i=\$implicit']);
|
||||||
|
|
||||||
bindings = parseTemplateBindings("var i-a = k-a");
|
bindings = parseTemplateBindings("let a; let b");
|
||||||
expect(keyValues(bindings)).toEqual(['#i-a=k-a']);
|
expect(keyValues(bindings)).toEqual(['let a=\$implicit', 'let b=\$implicit']);
|
||||||
|
|
||||||
bindings = parseTemplateBindings("keyword var item; var i = k");
|
bindings = parseTemplateBindings("let a; let b;");
|
||||||
expect(keyValues(bindings)).toEqual(['keyword', '#item=\$implicit', '#i=k']);
|
expect(keyValues(bindings)).toEqual(['let a=\$implicit', 'let b=\$implicit']);
|
||||||
|
|
||||||
bindings = parseTemplateBindings("keyword: #item; #i = k");
|
bindings = parseTemplateBindings("let i-a = k-a");
|
||||||
expect(keyValues(bindings)).toEqual(['keyword', '#item=\$implicit', '#i=k']);
|
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))
|
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', () => {
|
it('should parse pipes', () => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {print, IS_DART} from 'angular2/src/facade/lang';
|
import {print, IS_DART} from 'angular2/src/facade/lang';
|
||||||
import {OutputEmitter} from 'angular2/src/compiler/output/abstract_emitter';
|
import {OutputEmitter} from 'angular2/src/compiler/output/abstract_emitter';
|
||||||
|
import {Console} from 'angular2/src/core/console';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
OfflineCompiler,
|
OfflineCompiler,
|
||||||
|
@ -48,8 +49,8 @@ function _createOfflineCompiler(xhr: MockXHR, emitter: OutputEmitter): OfflineCo
|
||||||
var htmlParser = new HtmlParser();
|
var htmlParser = new HtmlParser();
|
||||||
var normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser);
|
var normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser);
|
||||||
return new OfflineCompiler(
|
return new OfflineCompiler(
|
||||||
normalizer,
|
normalizer, new TemplateParser(new Parser(new Lexer()), new MockSchemaRegistry({}, {}),
|
||||||
new TemplateParser(new Parser(new Lexer()), new MockSchemaRegistry({}, {}), htmlParser, []),
|
htmlParser, new Console(), []),
|
||||||
new StyleCompiler(urlResolver), new ViewCompiler(new CompilerConfig(true, true, true)),
|
new StyleCompiler(urlResolver), new ViewCompiler(new CompilerConfig(true, true, true)),
|
||||||
emitter);
|
emitter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
beforeEachProviders
|
beforeEachProviders
|
||||||
} from 'angular2/testing_internal';
|
} from 'angular2/testing_internal';
|
||||||
import {provide} from 'angular2/src/core/di';
|
import {provide} from 'angular2/src/core/di';
|
||||||
|
import {Console} from 'angular2/src/core/console';
|
||||||
|
|
||||||
import {TEST_PROVIDERS} from './test_bindings';
|
import {TEST_PROVIDERS} from './test_bindings';
|
||||||
import {isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
import {isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
|
@ -36,6 +37,7 @@ import {
|
||||||
NgContentAst,
|
NgContentAst,
|
||||||
EmbeddedTemplateAst,
|
EmbeddedTemplateAst,
|
||||||
ElementAst,
|
ElementAst,
|
||||||
|
ReferenceAst,
|
||||||
VariableAst,
|
VariableAst,
|
||||||
BoundEventAst,
|
BoundEventAst,
|
||||||
BoundElementPropertyAst,
|
BoundElementPropertyAst,
|
||||||
|
@ -47,6 +49,7 @@ import {
|
||||||
DirectiveAst,
|
DirectiveAst,
|
||||||
ProviderAstType
|
ProviderAstType
|
||||||
} from 'angular2/src/compiler/template_ast';
|
} 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 {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry';
|
||||||
import {MockSchemaRegistry} from './schema_registry_mock';
|
import {MockSchemaRegistry} from './schema_registry_mock';
|
||||||
|
@ -66,8 +69,13 @@ var MOCK_SCHEMA_REGISTRY = [
|
||||||
export function main() {
|
export function main() {
|
||||||
var ngIf;
|
var ngIf;
|
||||||
var parse;
|
var parse;
|
||||||
|
var console: ArrayConsole;
|
||||||
|
|
||||||
function commonBeforeEach() {
|
function commonBeforeEach() {
|
||||||
|
beforeEachProviders(() => {
|
||||||
|
console = new ArrayConsole();
|
||||||
|
return [provide(Console, {useValue: console})];
|
||||||
|
});
|
||||||
beforeEach(inject([TemplateParser], (parser) => {
|
beforeEach(inject([TemplateParser], (parser) => {
|
||||||
var component = CompileDirectiveMetadata.create({
|
var component = CompileDirectiveMetadata.create({
|
||||||
selector: 'root',
|
selector: 'root',
|
||||||
|
@ -310,7 +318,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('directives', () => {
|
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({
|
var dirA = CompileDirectiveMetadata.create({
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
|
@ -324,19 +332,14 @@ export function main() {
|
||||||
selector: '[c]',
|
selector: '[c]',
|
||||||
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirC'})
|
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirC'})
|
||||||
});
|
});
|
||||||
var comp = CompileDirectiveMetadata.create({
|
expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC])))
|
||||||
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])))
|
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div'],
|
[ElementAst, 'div'],
|
||||||
[AttrAst, 'a', ''],
|
[AttrAst, 'a', ''],
|
||||||
[AttrAst, 'c', ''],
|
[AttrAst, 'c', ''],
|
||||||
[AttrAst, 'b', ''],
|
[AttrAst, 'b', ''],
|
||||||
[DirectiveAst, comp],
|
[AttrAst, 'a', ''],
|
||||||
|
[AttrAst, 'b', ''],
|
||||||
[DirectiveAst, dirA],
|
[DirectiveAst, dirA],
|
||||||
[DirectiveAst, dirB],
|
[DirectiveAst, dirB],
|
||||||
[DirectiveAst, dirC]
|
[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>', [])))
|
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>', [])))
|
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', () => {
|
it('should parse camel case references', () => {
|
||||||
expect(humanizeTplAst(parse('<div var-someA>', [])))
|
expect(humanizeTplAst(parse('<div ref-someA>', [])))
|
||||||
.toEqual([[ElementAst, 'div'], [VariableAst, '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>', [])))
|
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({
|
var dirA = CompileDirectiveMetadata.create({
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}),
|
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}),
|
||||||
|
@ -779,28 +794,27 @@ export function main() {
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div'],
|
[ElementAst, 'div'],
|
||||||
[AttrAst, 'a', ''],
|
[AttrAst, 'a', ''],
|
||||||
|
[ReferenceAst, 'a', identifierToken(dirA.type)],
|
||||||
[DirectiveAst, dirA],
|
[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:
|
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`);
|
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:
|
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',
|
it('should report variables as errors', () => {
|
||||||
() => {
|
expect(() => parse('<div let-a></div>', [])).toThrowError(`Template parse errors:
|
||||||
expect(humanizeTplAst(parse('<template #a="b"></template>', [])))
|
"let-" is only supported on template elements. ("<div [ERROR ->]let-a></div>"): TestComp@0:5`);
|
||||||
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b']]);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should assign variables with empty value to components', () => {
|
it('should assign references with empty value to components', () => {
|
||||||
var dirA = CompileDirectiveMetadata.create({
|
var dirA = CompileDirectiveMetadata.create({
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
isComponent: true,
|
isComponent: true,
|
||||||
|
@ -812,12 +826,19 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div'],
|
[ElementAst, 'div'],
|
||||||
[AttrAst, 'a', ''],
|
[AttrAst, 'a', ''],
|
||||||
[VariableAst, 'a', ''],
|
[ReferenceAst, 'a', identifierToken(dirA.type)],
|
||||||
[DirectiveAst, dirA],
|
[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', () => {
|
describe('explicit templates', () => {
|
||||||
|
@ -836,6 +857,49 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
|
||||||
[EmbeddedTemplateAst],
|
[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', () => {
|
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 #...', () => {
|
it('should parse variables via #... and report them as deprecated', () => {
|
||||||
expect(humanizeTplAst(parse('<div template="ngIf #a=b">', [])))
|
expect(humanizeTplAst(parse('<div *ngIf="#a=b">', [])))
|
||||||
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
|
.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 ...', () => {
|
it('should parse variables via var ... and report them as deprecated', () => {
|
||||||
expect(humanizeTplAst(parse('<div template="ngIf var a=b">', [])))
|
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']]);
|
.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({
|
var dirA = CompileDirectiveMetadata.create({
|
||||||
selector: '[a=b]',
|
selector: '[a]',
|
||||||
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
|
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'})
|
||||||
});
|
});
|
||||||
var dirB = CompileDirectiveMetadata.create({
|
expect(humanizeTplAst(parse('<div template="let a=b">', [dirA])))
|
||||||
selector: '[b]',
|
.toEqual([[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']]);
|
||||||
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirB'})
|
});
|
||||||
|
|
||||||
|
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])))
|
expect(humanizeTplAst(parse('<div ref-a>', [dirA])))
|
||||||
.toEqual([
|
.toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]);
|
||||||
[EmbeddedTemplateAst],
|
|
||||||
[VariableAst, 'a', 'b'],
|
|
||||||
[DirectiveAst, dirA],
|
|
||||||
[ElementAst, 'div'],
|
|
||||||
[AttrAst, 'b', ''],
|
|
||||||
[DirectiveAst, dirB]
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -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', () => {
|
it('should support variables', () => {
|
||||||
var dirA = CompileDirectiveMetadata.create({
|
expect(humanizeTplAstSourceSpans(parse('<template let-a="b"></template>', [])))
|
||||||
selector: '[a]',
|
|
||||||
type: new CompileTypeMetadata({moduleUrl: someModuleUrl, name: 'DirA'}),
|
|
||||||
exportAs: 'dirA'
|
|
||||||
});
|
|
||||||
expect(humanizeTplAstSourceSpans(parse('<div a #a="dirA"></div>', [dirA])))
|
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div', '<div a #a="dirA">'],
|
[EmbeddedTemplateAst, '<template let-a="b">'],
|
||||||
[AttrAst, 'a', '', 'a'],
|
[VariableAst, 'a', 'b', 'let-a="b"']
|
||||||
[DirectiveAst, dirA, '<div a #a="dirA">'],
|
|
||||||
[VariableAst, 'a', 'dirA', '#a="dirA"']
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support event', () => {
|
it('should support events', () => {
|
||||||
expect(humanizeTplAstSourceSpans(parse('<div (window:event)="v">', [])))
|
expect(humanizeTplAstSourceSpans(parse('<div (window:event)="v">', [])))
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div', '<div (window:event)="v">'],
|
[ElementAst, 'div', '<div (window:event)="v">'],
|
||||||
|
@ -1311,8 +1390,8 @@ Property binding a not used by any directive on an embedded template ("[ERROR ->
|
||||||
.toEqual([
|
.toEqual([
|
||||||
[ElementAst, 'div', '<div a>'],
|
[ElementAst, 'div', '<div a>'],
|
||||||
[AttrAst, 'a', '', 'a'],
|
[AttrAst, 'a', '', 'a'],
|
||||||
[DirectiveAst, comp, '<div a>'],
|
|
||||||
[DirectiveAst, dirA, '<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));
|
this.result.push(this._appendContext(ast, res));
|
||||||
templateVisitAll(this, ast.attrs);
|
templateVisitAll(this, ast.attrs);
|
||||||
templateVisitAll(this, ast.outputs);
|
templateVisitAll(this, ast.outputs);
|
||||||
templateVisitAll(this, ast.vars);
|
templateVisitAll(this, ast.references);
|
||||||
|
templateVisitAll(this, ast.variables);
|
||||||
templateVisitAll(this, ast.directives);
|
templateVisitAll(this, ast.directives);
|
||||||
templateVisitAll(this, ast.children);
|
templateVisitAll(this, ast.children);
|
||||||
return null;
|
return null;
|
||||||
|
@ -1410,11 +1490,16 @@ class TemplateHumanizer implements TemplateAstVisitor {
|
||||||
templateVisitAll(this, ast.attrs);
|
templateVisitAll(this, ast.attrs);
|
||||||
templateVisitAll(this, ast.inputs);
|
templateVisitAll(this, ast.inputs);
|
||||||
templateVisitAll(this, ast.outputs);
|
templateVisitAll(this, ast.outputs);
|
||||||
templateVisitAll(this, ast.exportAsVars);
|
templateVisitAll(this, ast.references);
|
||||||
templateVisitAll(this, ast.directives);
|
templateVisitAll(this, ast.directives);
|
||||||
templateVisitAll(this, ast.children);
|
templateVisitAll(this, ast.children);
|
||||||
return null;
|
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 {
|
visitVariable(ast: VariableAst, context: any): any {
|
||||||
var res = [VariableAst, ast.name, ast.value];
|
var res = [VariableAst, ast.name, ast.value];
|
||||||
this.result.push(this._appendContext(ast, res));
|
this.result.push(this._appendContext(ast, res));
|
||||||
|
@ -1457,7 +1542,6 @@ class TemplateHumanizer implements TemplateAstVisitor {
|
||||||
templateVisitAll(this, ast.inputs);
|
templateVisitAll(this, ast.inputs);
|
||||||
templateVisitAll(this, ast.hostProperties);
|
templateVisitAll(this, ast.hostProperties);
|
||||||
templateVisitAll(this, ast.hostEvents);
|
templateVisitAll(this, ast.hostEvents);
|
||||||
templateVisitAll(this, ast.exportAsVars);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
|
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
|
||||||
|
@ -1499,6 +1583,7 @@ class TemplateContentProjectionHumanizer implements TemplateAstVisitor {
|
||||||
templateVisitAll(this, ast.children);
|
templateVisitAll(this, ast.children);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
visitReference(ast: ReferenceAst, context: any): any { return null; }
|
||||||
visitVariable(ast: VariableAst, context: any): any { return null; }
|
visitVariable(ast: VariableAst, context: any): any { return null; }
|
||||||
visitEvent(ast: BoundEventAst, context: any): any { return null; }
|
visitEvent(ast: BoundEventAst, context: any): any { return null; }
|
||||||
visitElementProperty(ast: BoundElementPropertyAst, 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,
|
return new ElementAst('foo', [], [], [], [], [], [], false, [], ast.ngContentIndex,
|
||||||
ast.sourceSpan);
|
ast.sourceSpan);
|
||||||
}
|
}
|
||||||
|
visitReference(ast: ReferenceAst, context: any): any { throw 'not implemented'; }
|
||||||
visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; }
|
visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; }
|
||||||
visitEvent(ast: BoundEventAst, context: any): any { throw 'not implemented'; }
|
visitEvent(ast: BoundEventAst, context: any): any { throw 'not implemented'; }
|
||||||
visitElementProperty(ast: BoundElementPropertyAst, 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);
|
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 {
|
class _MockConsole implements Console {
|
||||||
log(message) {}
|
log(message) {}
|
||||||
|
warn(message) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,9 +132,9 @@ class ConditionalParentComp {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'using-for',
|
selector: 'using-for',
|
||||||
viewProviders: [Logger],
|
viewProviders: [Logger],
|
||||||
template: `<span *ngFor="#thing of stuff" [innerHtml]="thing"></span>
|
template: `<span *ngFor="let thing of stuff" [innerHtml]="thing"></span>
|
||||||
<ul message="list">
|
<ul message="list">
|
||||||
<li *ngFor="#item of stuff" [innerHtml]="item"></li>
|
<li *ngFor="let item of stuff" [innerHtml]="item"></li>
|
||||||
</ul>`,
|
</ul>`,
|
||||||
directives: [NgFor, MessageDir],
|
directives: [NgFor, MessageDir],
|
||||||
})
|
})
|
||||||
|
|
|
@ -50,7 +50,7 @@ class App {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'lock',
|
selector: 'lock',
|
||||||
directives: [NgFor],
|
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 {
|
class Door {
|
||||||
locks: QueryList<Lock>;
|
locks: QueryList<Lock>;
|
||||||
|
|
|
@ -438,7 +438,7 @@ export function main() {
|
||||||
|
|
||||||
it('should read locals', fakeAsync(() => {
|
it('should read locals', fakeAsync(() => {
|
||||||
var ctx =
|
var ctx =
|
||||||
createCompFixture('<template testLocals var-local="someLocal">{{local}}</template>');
|
createCompFixture('<template testLocals let-local="someLocal">{{local}}</template>');
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
|
|
||||||
expect(renderLog.log).toEqual(['{{someLocalValue}}']);
|
expect(renderLog.log).toEqual(['{{someLocalValue}}']);
|
||||||
|
@ -581,7 +581,7 @@ export function main() {
|
||||||
|
|
||||||
it('should throw when trying to assign to a local', fakeAsync(() => {
|
it('should throw when trying to assign to a local', fakeAsync(() => {
|
||||||
expect(() => {_bindSimpleProp('(event)="$event=1"')})
|
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(() => {
|
it('should support short-circuiting', fakeAsync(() => {
|
||||||
|
@ -609,7 +609,7 @@ export function main() {
|
||||||
it('should read directive properties', fakeAsync(() => {
|
it('should read directive properties', fakeAsync(() => {
|
||||||
var ctx =
|
var ctx =
|
||||||
createCompFixture(
|
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);
|
ctx.detectChanges(false);
|
||||||
expect(renderLog.loggedValues).toEqual([42]);
|
expect(renderLog.loggedValues).toEqual([42]);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -259,7 +259,7 @@ class OnChangeComponent implements OnChanges {
|
||||||
])
|
])
|
||||||
@View(
|
@View(
|
||||||
template:
|
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])
|
directives: const [NgFor, DirectiveLoggingChecks])
|
||||||
class ComponentWithObservableList {
|
class ComponentWithObservableList {
|
||||||
Iterable list;
|
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 {ComponentResolver} from 'angular2/src/core/linker/component_resolver';
|
||||||
import {ElementRef} from 'angular2/src/core/linker/element_ref';
|
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';
|
import {Renderer} from 'angular2/src/core/render';
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ function declareTests(isJit: boolean) {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [SomeViewport]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -509,7 +509,7 @@ function declareTests(isJit: boolean) {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [SomeViewport]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ function declareTests(isJit: boolean) {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [SomeDirective, CompWithHost, ToolbarComponent, ToolbarPart]
|
||||||
}))
|
}))
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -547,12 +547,12 @@ function declareTests(isJit: boolean) {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("variable bindings", () => {
|
describe("reference bindings", () => {
|
||||||
it('should assign a component to a var-',
|
it('should assign a component to a ref-',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter],
|
inject([TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MyComp, new ViewMetadata({
|
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]
|
directives: [ChildComp]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ function declareTests(isJit: boolean) {
|
||||||
async.done();
|
async.done();
|
||||||
})}));
|
})}));
|
||||||
|
|
||||||
it('should assign a directive to a var-',
|
it('should assign a directive to a ref-',
|
||||||
inject(
|
inject(
|
||||||
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MyComp, new ViewMetadata({
|
tcb.overrideView(MyComp, new ViewMetadata({
|
||||||
|
@ -588,7 +588,7 @@ function declareTests(isJit: boolean) {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [ChildComp, NgIf]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -600,14 +600,14 @@ function declareTests(isJit: boolean) {
|
||||||
async.done();
|
async.done();
|
||||||
})}));
|
})}));
|
||||||
|
|
||||||
it('should assign two component instances each with a var-',
|
it('should assign two component instances each with a ref-',
|
||||||
inject(
|
inject(
|
||||||
[TestComponentBuilder, AsyncTestCompleter],
|
[TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [ChildComp]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ function declareTests(isJit: boolean) {
|
||||||
async.done();
|
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],
|
inject([TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder,
|
(tcb: TestComponentBuilder,
|
||||||
async) => {tcb.overrideView(MyComp, new ViewMetadata({
|
async) => {tcb.overrideView(MyComp, new ViewMetadata({
|
||||||
|
@ -643,7 +643,7 @@ function declareTests(isJit: boolean) {
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter],
|
inject([TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MyComp, new ViewMetadata({
|
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)
|
.createAsync(MyComp)
|
||||||
|
@ -657,11 +657,26 @@ function declareTests(isJit: boolean) {
|
||||||
async.done();
|
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',
|
it('should preserve case',
|
||||||
inject(
|
inject(
|
||||||
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MyComp, new ViewMetadata({
|
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]
|
directives: [ChildComp]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -673,14 +688,16 @@ function declareTests(isJit: boolean) {
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('variables', () => {
|
||||||
it('should allow to use variables in a for loop',
|
it('should allow to use variables in a for loop',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder,
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder,
|
||||||
async) => {
|
async) => {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
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]
|
directives: [ChildCompNoTemplate, NgFor]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -2281,7 +2298,7 @@ class ToolbarViewContainer {
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'toolbar',
|
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]
|
directives: [ToolbarViewContainer, NgFor]
|
||||||
})
|
})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -2489,7 +2506,7 @@ class DirectiveThrowingAnError {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'component-with-template',
|
selector: 'component-with-template',
|
||||||
directives: [NgFor],
|
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 {
|
class ComponentWithTemplate {
|
||||||
items = [1, 2, 3];
|
items = [1, 2, 3];
|
||||||
|
|
|
@ -246,7 +246,7 @@ export function main() {
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template =
|
var template =
|
||||||
'<div text="1"></div>' +
|
'<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>';
|
'<div text="4"></div>';
|
||||||
|
|
||||||
tcb.overrideTemplate(MyComp, template)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
|
@ -268,7 +268,7 @@ export function main() {
|
||||||
describe('query for TemplateRef', () => {
|
describe('query for TemplateRef', () => {
|
||||||
it('should find TemplateRefs in the light and shadow dom',
|
it('should find TemplateRefs in the light and shadow dom',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
.then((view) => {
|
.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', () => {
|
describe('read a different token', () => {
|
||||||
|
@ -462,9 +479,10 @@ export function main() {
|
||||||
describe("querying by var binding", () => {
|
describe("querying by var binding", () => {
|
||||||
it('should contain all the child directives in the light dom with the given var binding',
|
it('should contain all the child directives in the light dom with the given var binding',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<needs-query-by-var-binding #q>' +
|
var template =
|
||||||
'<div *ngFor="#item of list" [text]="item" #textLabel="textDir"></div>' +
|
'<needs-query-by-ref-binding #q>' +
|
||||||
'</needs-query-by-var-binding>';
|
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
|
||||||
|
'</needs-query-by-ref-binding>';
|
||||||
|
|
||||||
tcb.overrideTemplate(MyComp, template)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -484,10 +502,10 @@ export function main() {
|
||||||
|
|
||||||
it('should support querying by multiple var bindings',
|
it('should support querying by multiple var bindings',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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="one" #textLabel1="textDir"></div>' +
|
||||||
'<div text="two" #textLabel2="textDir"></div>' +
|
'<div text="two" #textLabel2="textDir"></div>' +
|
||||||
'</needs-query-by-var-bindings>';
|
'</needs-query-by-ref-bindings>';
|
||||||
|
|
||||||
tcb.overrideTemplate(MyComp, template)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -504,9 +522,10 @@ export function main() {
|
||||||
|
|
||||||
it('should support dynamically inserted directives',
|
it('should support dynamically inserted directives',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<needs-query-by-var-binding #q>' +
|
var template =
|
||||||
'<div *ngFor="#item of list" [text]="item" #textLabel="textDir"></div>' +
|
'<needs-query-by-ref-binding #q>' +
|
||||||
'</needs-query-by-var-binding>';
|
'<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' +
|
||||||
|
'</needs-query-by-ref-binding>';
|
||||||
|
|
||||||
tcb.overrideTemplate(MyComp, template)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -529,11 +548,11 @@ export function main() {
|
||||||
|
|
||||||
it('should contain all the elements in the light dom with the given var binding',
|
it('should contain all the elements in the light dom with the given var binding',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<needs-query-by-var-binding #q>' +
|
var template = '<needs-query-by-ref-binding #q>' +
|
||||||
'<div template="ngFor: #item of list">' +
|
'<div template="ngFor: let item of list">' +
|
||||||
'<div #textLabel>{{item}}</div>' +
|
'<div #textLabel>{{item}}</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</needs-query-by-var-binding>';
|
'</needs-query-by-ref-binding>';
|
||||||
|
|
||||||
tcb.overrideTemplate(MyComp, template)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -570,7 +589,7 @@ export function main() {
|
||||||
|
|
||||||
it('should support querying the view by using a view query',
|
it('should support querying the view by using a view query',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(MyComp, template)
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
|
@ -859,7 +878,7 @@ class InertDirective {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'needs-query',
|
selector: 'needs-query',
|
||||||
directives: [NgFor, TextDirective],
|
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()
|
@Injectable()
|
||||||
class NeedsQuery {
|
class NeedsQuery {
|
||||||
|
@ -878,7 +897,7 @@ class NeedsFourQueries {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'needs-query-desc',
|
selector: 'needs-query-desc',
|
||||||
directives: [NgFor],
|
directives: [NgFor],
|
||||||
template: '<div *ngFor="var dir of query">{{dir.text}}|</div>'
|
template: '<div *ngFor="let dir of query">{{dir.text}}|</div>'
|
||||||
})
|
})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class NeedsQueryDesc {
|
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()
|
@Injectable()
|
||||||
class NeedsQueryByLabel {
|
class NeedsQueryByLabel {
|
||||||
query: QueryList<any>;
|
query: QueryList<any>;
|
||||||
|
@ -898,7 +917,7 @@ class NeedsQueryByLabel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'needs-view-query-by-var-binding',
|
selector: 'needs-view-query-by-ref-binding',
|
||||||
directives: [],
|
directives: [],
|
||||||
template: '<div #textLabel>text</div>'
|
template: '<div #textLabel>text</div>'
|
||||||
})
|
})
|
||||||
|
@ -908,7 +927,7 @@ class NeedsViewQueryByLabel {
|
||||||
constructor(@ViewQuery("textLabel") query: QueryList<any>) { this.query = query; }
|
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()
|
@Injectable()
|
||||||
class NeedsQueryByTwoLabels {
|
class NeedsQueryByTwoLabels {
|
||||||
query: QueryList<any>;
|
query: QueryList<any>;
|
||||||
|
@ -920,7 +939,7 @@ class NeedsQueryByTwoLabels {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'needs-query-and-project',
|
selector: 'needs-query-and-project',
|
||||||
directives: [NgFor],
|
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()
|
@Injectable()
|
||||||
class NeedsQueryAndProject {
|
class NeedsQueryAndProject {
|
||||||
|
@ -975,7 +994,7 @@ class NeedsViewQueryNestedIf {
|
||||||
selector: 'needs-view-query-order',
|
selector: 'needs-view-query-order',
|
||||||
directives: [NgFor, TextDirective, InertDirective],
|
directives: [NgFor, TextDirective, InertDirective],
|
||||||
template: '<div text="1"></div>' +
|
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>'
|
'<div text="4"></div>'
|
||||||
})
|
})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -992,7 +1011,7 @@ class NeedsViewQueryOrder {
|
||||||
selector: 'needs-view-query-order-with-p',
|
selector: 'needs-view-query-order-with-p',
|
||||||
directives: [NgFor, TextDirective, InertDirective],
|
directives: [NgFor, TextDirective, InertDirective],
|
||||||
template: '<div dir><div text="1"></div>' +
|
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>'
|
'<div text="4"></div></div>'
|
||||||
})
|
})
|
||||||
@Injectable()
|
@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 {
|
class NeedsTpl {
|
||||||
viewQuery: QueryList<TemplateRef>;
|
viewQuery: QueryList<TemplateRef>;
|
||||||
query: 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: ''})
|
@Component({selector: 'needs-content-children-read', template: ''})
|
||||||
class NeedsContentChildrenWithRead {
|
class NeedsContentChildrenWithRead {
|
||||||
@ContentChildren('q', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
|
@ContentChildren('q', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
|
||||||
|
@ -1076,6 +1102,7 @@ class NeedsViewContainerWithRead {
|
||||||
NeedsViewChild,
|
NeedsViewChild,
|
||||||
NeedsContentChild,
|
NeedsContentChild,
|
||||||
NeedsTpl,
|
NeedsTpl,
|
||||||
|
NeedsNamedTpl,
|
||||||
TextDirective,
|
TextDirective,
|
||||||
InertDirective,
|
InertDirective,
|
||||||
NgIf,
|
NgIf,
|
||||||
|
@ -1097,4 +1124,4 @@ class MyComp {
|
||||||
this.shouldShow = false;
|
this.shouldShow = false;
|
||||||
this.list = ['1d', '2d', '3d'];
|
this.list = ['1d', '2d', '3d'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ class _ArrayLogger {
|
||||||
|
|
||||||
class DummyConsole implements Console {
|
class DummyConsole implements Console {
|
||||||
log(message) {}
|
log(message) {}
|
||||||
|
warn(message) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
|
|
@ -116,6 +116,7 @@ var NG_COMPILER = [
|
||||||
"TEMPLATE_TRANSFORMS",
|
"TEMPLATE_TRANSFORMS",
|
||||||
"TextAst",
|
"TextAst",
|
||||||
"VariableAst",
|
"VariableAst",
|
||||||
|
"ReferenceAst",
|
||||||
"XHR",
|
"XHR",
|
||||||
"templateVisitAll",
|
"templateVisitAll",
|
||||||
"CompileDiDependencyMetadata",
|
"CompileDiDependencyMetadata",
|
||||||
|
|
|
@ -43,6 +43,7 @@ import {MockApplicationRef} from 'angular2/src/mock/mock_application_ref';
|
||||||
|
|
||||||
class DummyConsole implements Console {
|
class DummyConsole implements Console {
|
||||||
log(message) {}
|
log(message) {}
|
||||||
|
warn(message) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
|
|
@ -35,6 +35,7 @@ class _ArrayLogger {
|
||||||
|
|
||||||
class DummyConsole implements Console {
|
class DummyConsole implements Console {
|
||||||
log(message) {}
|
log(message) {}
|
||||||
|
warn(message) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
|
|
@ -63,15 +63,15 @@ class DynamicDummy {
|
||||||
directives: [NgIf, NgFor, DummyComponent, DummyDirective, DynamicDummy],
|
directives: [NgIf, NgFor, DummyComponent, DummyDirective, DynamicDummy],
|
||||||
template: `
|
template: `
|
||||||
<div *ngIf="testingPlainComponents">
|
<div *ngIf="testingPlainComponents">
|
||||||
<dummy *ngFor="#i of list"></dummy>
|
<dummy *ngFor="let i of list"></dummy>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="testingWithDirectives">
|
<div *ngIf="testingWithDirectives">
|
||||||
<dummy dummy-decorator *ngFor="#i of list"></dummy>
|
<dummy dummy-decorator *ngFor="let i of list"></dummy>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="testingDynamicComponents">
|
<div *ngIf="testingDynamicComponents">
|
||||||
<dynamic-dummy *ngFor="#i of list"></dynamic-dummy>
|
<dynamic-dummy *ngFor="let i of list"></dynamic-dummy>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
|
|
@ -214,22 +214,22 @@ class CellData {
|
||||||
template: `
|
template: `
|
||||||
<table [ngSwitch]="benchmarkType">
|
<table [ngSwitch]="benchmarkType">
|
||||||
<tbody template="ngSwitchWhen 'interpolation'">
|
<tbody template="ngSwitchWhen 'interpolation'">
|
||||||
<tr template="ngFor #row of data">
|
<tr template="ngFor let row of data">
|
||||||
<td template="ngFor #column of row">
|
<td template="ngFor let column of row">
|
||||||
{{column.i}}:{{column.j}}|
|
{{column.i}}:{{column.j}}|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody template="ngSwitchWhen 'interpolationAttr'">
|
<tbody template="ngSwitchWhen 'interpolationAttr'">
|
||||||
<tr template="ngFor #row of data">
|
<tr template="ngFor let row of data">
|
||||||
<td template="ngFor #column of row" attr.i="{{column.i}}" attr.j="{{column.j}}">
|
<td template="ngFor let column of row" attr.i="{{column.i}}" attr.j="{{column.j}}">
|
||||||
i,j attrs
|
i,j attrs
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody template="ngSwitchWhen 'interpolationFn'">
|
<tbody template="ngSwitchWhen 'interpolationFn'">
|
||||||
<tr template="ngFor #row of data">
|
<tr template="ngFor let row of data">
|
||||||
<td template="ngFor #column of row">
|
<td template="ngFor let column of row">
|
||||||
{{column.iFn()}}:{{column.jFn()}}|
|
{{column.iFn()}}:{{column.jFn()}}|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {Component, Directive} from 'angular2/core';
|
||||||
</div>
|
</div>
|
||||||
<div template="ngIf scrollAreas.length > 0">
|
<div template="ngIf scrollAreas.length > 0">
|
||||||
<p>Following tables are only here to add weight to the UI:</p>
|
<p>Following tables are only here to add weight to the UI:</p>
|
||||||
<scroll-area template="ngFor #scrollArea of scrollAreas"></scroll-area>
|
<scroll-area template="ngFor let scrollArea of scrollAreas"></scroll-area>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
|
@ -55,7 +55,7 @@ export class Stage {
|
||||||
directives: [NgFor],
|
directives: [NgFor],
|
||||||
template: `
|
template: `
|
||||||
<div [style.width.px]="cellWidth">
|
<div [style.width.px]="cellWidth">
|
||||||
<button template="ngFor #stage of stages"
|
<button template="ngFor let stage of stages"
|
||||||
[disabled]="stage.isDisabled"
|
[disabled]="stage.isDisabled"
|
||||||
[style.background-color]="stage.backgroundColor"
|
[style.background-color]="stage.backgroundColor"
|
||||||
on-click="setStage(stage)">
|
on-click="setStage(stage)">
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {NgFor} from 'angular2/common';
|
||||||
<div id="padding"></div>
|
<div id="padding"></div>
|
||||||
<div id="inner">
|
<div id="inner">
|
||||||
<scroll-item
|
<scroll-item
|
||||||
template="ngFor #item of visibleItems"
|
template="ngFor let item of visibleItems"
|
||||||
[offering]="item">
|
[offering]="item">
|
||||||
</scroll-item>
|
</scroll-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'rxjs/add/operator/map';
|
||||||
template: `
|
template: `
|
||||||
<h1>people</h1>
|
<h1>people</h1>
|
||||||
<ul class="people">
|
<ul class="people">
|
||||||
<li *ngFor="#person of people">
|
<li *ngFor="let person of people">
|
||||||
hello, {{person['name']}}
|
hello, {{person['name']}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
template: `
|
template: `
|
||||||
<h1>people</h1>
|
<h1>people</h1>
|
||||||
<ul class="people">
|
<ul class="people">
|
||||||
<li *ngFor="#person of people">
|
<li *ngFor="let person of people">
|
||||||
hello, {{person['name']}}
|
hello, {{person['name']}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -102,7 +102,7 @@ class ShowError {
|
||||||
<p>
|
<p>
|
||||||
<label for="country">Country</label>
|
<label for="country">Country</label>
|
||||||
<select id="country" ngControl="country">
|
<select id="country" ngControl="country">
|
||||||
<option *ngFor="#c of countries" [value]="c">{{c}}</option>
|
<option *ngFor="let c of countries" [value]="c">{{c}}</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ class DataService {
|
||||||
selector: 'order-list-cmp',
|
selector: 'order-list-cmp',
|
||||||
template: `
|
template: `
|
||||||
<h1>Orders</h1>
|
<h1>Orders</h1>
|
||||||
<div *ngFor="#order of orders" [class.warning]="order.total > order.limit">
|
<div *ngFor="let order of orders" [class.warning]="order.total > order.limit">
|
||||||
<div>
|
<div>
|
||||||
<label>Customer name:</label>
|
<label>Customer name:</label>
|
||||||
{{order.customerName}}
|
{{order.customerName}}
|
||||||
|
@ -173,7 +173,7 @@ class OrderItemComponent {
|
||||||
|
|
||||||
<h2>Items</h2>
|
<h2>Items</h2>
|
||||||
<button (click)="addItem()">Add Item</button>
|
<button (click)="addItem()">Add Item</button>
|
||||||
<order-item-cmp *ngFor="#item of order.items" [item]="item" (delete)="deleteItem(item)"></order-item-cmp>
|
<order-item-cmp *ngFor="let item of order.items" [item]="item" (delete)="deleteItem(item)"></order-item-cmp>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
directives: [FORM_DIRECTIVES, OrderItemComponent, NgFor, NgIf]
|
directives: [FORM_DIRECTIVES, OrderItemComponent, NgFor, NgIf]
|
||||||
|
|
|
@ -161,7 +161,7 @@ class PersonsDetailComponent {
|
||||||
<h1>FullName Demo</h1>
|
<h1>FullName Demo</h1>
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="#person of persons">
|
<li *ngFor="let person of persons">
|
||||||
<label (click)="select(person)">{{person.fullName}}</label>
|
<label (click)="select(person)">{{person.fullName}}</label>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<h2 class="page-title">Drafts</h2>
|
<h2 class="page-title">Drafts</h2>
|
||||||
|
|
||||||
<ol class="inbox-list">
|
<ol class="inbox-list">
|
||||||
<li *ngFor="#item of items" class="inbox-item-record">
|
<li *ngFor="let item of items" class="inbox-item-record">
|
||||||
<a id="item-{{ item.id }}"
|
<a id="item-{{ item.id }}"
|
||||||
[routerLink]="['/DetailPage', {'id':item.id}]">
|
[routerLink]="['/DetailPage', {'id':item.id}]">
|
||||||
{{ item.subject }}</a>
|
{{ item.subject }}</a>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<h2 class="page-title">Inbox</h2>
|
<h2 class="page-title">Inbox</h2>
|
||||||
|
|
||||||
<ol class="inbox-list">
|
<ol class="inbox-list">
|
||||||
<li *ngFor="#item of items" class="inbox-item-record">
|
<li *ngFor="let item of items" class="inbox-item-record">
|
||||||
<a id="item-{{ item.id }}"
|
<a id="item-{{ item.id }}"
|
||||||
[routerLink]="['/DetailPage', {'id':item.id}]">{{ item.subject }}</a>
|
[routerLink]="['/DetailPage', {'id':item.id}]">{{ item.subject }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -122,7 +122,7 @@ class ShowError {
|
||||||
<p>
|
<p>
|
||||||
<label for="country">Country</label>
|
<label for="country">Country</label>
|
||||||
<select id="country" ngControl="country" [(ngModel)]="model.country">
|
<select id="country" ngControl="country" [(ngModel)]="model.country">
|
||||||
<option *ngFor="#c of countries" [value]="c">{{c}}</option>
|
<option *ngFor="let c of countries" [value]="c">{{c}}</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<ul id="todo-list">
|
<ul id="todo-list">
|
||||||
|
|
||||||
<li *ngFor="#todo of todoStore.list">
|
<li *ngFor="let todo of todoStore.list">
|
||||||
|
|
||||||
<div class="view"
|
<div class="view"
|
||||||
[class.hidden]="todoEdit == todo">
|
[class.hidden]="todoEdit == todo">
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
<section id="main" class="container">
|
<section id="main" class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div *ngFor="#image of images" class="col s12 m2">
|
<div *ngFor="let image of images" class="col s12 m2">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-image">
|
<div class="card-image">
|
||||||
<img [src]="image.src" [class.grey]="image.filtering"/>
|
<img [src]="image.src" [class.grey]="image.filtering"/>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<ul id="todo-list">
|
<ul id="todo-list">
|
||||||
|
|
||||||
<li *ngFor="#todo of todoStore.list" [class.hidden]="hideActive && !todo.completed || hideCompleted && todo.completed">
|
<li *ngFor="let todo of todoStore.list" [class.hidden]="hideActive && !todo.completed || hideCompleted && todo.completed">
|
||||||
<div class="view"
|
<div class="view"
|
||||||
[class.hidden]="todoEdit == todo">
|
[class.hidden]="todoEdit == todo">
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {Zippy} from './zippy';
|
||||||
This is some content.
|
This is some content.
|
||||||
</zippy>
|
</zippy>
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="var log of logs">{{log}}</li>
|
<li *ngFor="let log of logs">{{log}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
`,
|
`,
|
||||||
directives: [Zippy]
|
directives: [Zippy]
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ExternalTemplateComponent {
|
||||||
class MyToken {}
|
class MyToken {}
|
||||||
|
|
||||||
const TEMPLATE =
|
const 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>';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
initAngularTests();
|
initAngularTests();
|
||||||
|
|
|
@ -2,6 +2,7 @@ library angular2.transform.template_compiler.ng_compiler;
|
||||||
|
|
||||||
import 'package:angular2/src/compiler/config.dart';
|
import 'package:angular2/src/compiler/config.dart';
|
||||||
import 'package:angular2/src/compiler/view_compiler/view_compiler.dart';
|
import 'package:angular2/src/compiler/view_compiler/view_compiler.dart';
|
||||||
|
import 'package:angular2/src/core/console.dart';
|
||||||
import 'package:angular2/src/compiler/html_parser.dart';
|
import 'package:angular2/src/compiler/html_parser.dart';
|
||||||
import 'package:angular2/src/compiler/style_compiler.dart';
|
import 'package:angular2/src/compiler/style_compiler.dart';
|
||||||
import 'package:angular2/src/compiler/offline_compiler.dart';
|
import 'package:angular2/src/compiler/offline_compiler.dart';
|
||||||
|
@ -31,6 +32,7 @@ OfflineCompiler createTemplateCompiler(AssetReader reader,
|
||||||
parser,
|
parser,
|
||||||
new DomElementSchemaRegistry(),
|
new DomElementSchemaRegistry(),
|
||||||
_htmlParser,
|
_htmlParser,
|
||||||
|
new Console(),
|
||||||
[new RouterLinkTransform(parser)]);
|
[new RouterLinkTransform(parser)]);
|
||||||
|
|
||||||
return new OfflineCompiler(
|
return new OfflineCompiler(
|
||||||
|
|
|
@ -848,15 +848,14 @@ const COMPILER = [
|
||||||
'BoundTextAst.constructor(value:AST, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
'BoundTextAst.constructor(value:AST, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
||||||
'BoundTextAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
'BoundTextAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
'DirectiveAst',
|
'DirectiveAst',
|
||||||
'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)',
|
'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], sourceSpan:ParseSourceSpan)',
|
||||||
'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
'ElementAst',
|
'ElementAst',
|
||||||
'ElementAst.constructor(name:string, attrs:AttrAst[], inputs:BoundElementPropertyAst[], outputs:BoundEventAst[], exportAsVars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
'ElementAst.constructor(name:string, attrs:AttrAst[], inputs:BoundElementPropertyAst[], outputs:BoundEventAst[], references:ReferenceAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
||||||
'ElementAst.getComponent():CompileDirectiveMetadata',
|
'ElementAst.getComponent():CompileDirectiveMetadata',
|
||||||
'ElementAst.isBound():boolean',
|
|
||||||
'ElementAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
'ElementAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
'EmbeddedTemplateAst',
|
'EmbeddedTemplateAst',
|
||||||
'EmbeddedTemplateAst.constructor(attrs:AttrAst[], outputs:BoundEventAst[], vars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
'EmbeddedTemplateAst.constructor(attrs:AttrAst[], outputs:BoundEventAst[], references:ReferenceAst[], variables:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
||||||
'EmbeddedTemplateAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
'EmbeddedTemplateAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
'NgContentAst',
|
'NgContentAst',
|
||||||
'NgContentAst.constructor(index:number, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
'NgContentAst.constructor(index:number, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
|
||||||
|
@ -890,6 +889,10 @@ const COMPILER = [
|
||||||
'VariableAst',
|
'VariableAst',
|
||||||
'VariableAst.constructor(name:string, value:string, sourceSpan:ParseSourceSpan)',
|
'VariableAst.constructor(name:string, value:string, sourceSpan:ParseSourceSpan)',
|
||||||
'VariableAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
'VariableAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
|
'ReferenceAst',
|
||||||
|
'ReferenceAst.constructor(name:string, value:CompileTokenMetadata, sourceSpan:ParseSourceSpan)',
|
||||||
|
'ReferenceAst.visit(visitor:TemplateAstVisitor, context:any):any',
|
||||||
|
'TemplateAstVisitor.visitReference(ast:ReferenceAst, context:any):any',
|
||||||
'XHR',
|
'XHR',
|
||||||
'XHR.get(url:string):Promise<string>',
|
'XHR.get(url:string):Promise<string>',
|
||||||
'const COMPILER_PROVIDERS:Array<Type|Provider|any[]>',
|
'const COMPILER_PROVIDERS:Array<Type|Provider|any[]>',
|
||||||
|
|
Loading…
Reference in New Issue