diff --git a/modules/@angular/compiler/src/template_parser.ts b/modules/@angular/compiler/src/template_parser.ts index 3f395c70c7..c01bbea4c1 100644 --- a/modules/@angular/compiler/src/template_parser.ts +++ b/modules/@angular/compiler/src/template_parser.ts @@ -140,21 +140,24 @@ export class TemplateParser { directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[], templateUrl: string): TemplateParseResult { var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl); - var errors: ParseError[] = htmlAstWithErrors.errors; + var errors:ParseError[] = htmlAstWithErrors.errors; var result; if (htmlAstWithErrors.rootNodes.length > 0) { var uniqDirectives = removeDuplicates(directives); var uniqPipes = removeDuplicates(pipes); var providerViewContext = - new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan); + new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan); var parseVisitor = new TemplateParseVisitor(providerViewContext, uniqDirectives, uniqPipes, - this._exprParser, this._schemaRegistry); + this._exprParser, this._schemaRegistry); result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT); errors = errors.concat(parseVisitor.errors).concat(providerViewContext.errors); } else { result = []; } + + this._assertNoReferenceDuplicationOnTemplate(result, errors); + if (errors.length > 0) { return new TemplateParseResult(result, errors); } @@ -164,6 +167,25 @@ export class TemplateParser { } return new TemplateParseResult(result, errors); } + + _assertNoReferenceDuplicationOnTemplate(result:any[], errors:TemplateParseError[]):void { + const existingReferences = []; + result + .filter(element => !!element.references) + .forEach(element => element.references.forEach(reference=> { + const name = reference.name; + if (existingReferences.indexOf(name) < 0) { + existingReferences.push(name); + } + else { + const error = new TemplateParseError( + `Reference "#${name}" is defined several times`, + reference.sourceSpan, + ParseErrorLevel.FATAL); + errors.push(error); + } + })); + } } class TemplateParseVisitor implements HtmlAstVisitor { @@ -522,9 +544,11 @@ class TemplateParseVisitor implements HtmlAstVisitor { private _parseVariable(identifier: string, value: string, sourceSpan: ParseSourceSpan, targetVars: VariableAst[]) { + if (identifier.indexOf('-') > -1) { this._reportError(`"-" is not allowed in variable names`, sourceSpan); } + targetVars.push(new VariableAst(identifier, value, sourceSpan)); } @@ -533,6 +557,7 @@ class TemplateParseVisitor implements HtmlAstVisitor { if (identifier.indexOf('-') > -1) { this._reportError(`"-" is not allowed in reference names`, sourceSpan); } + targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan)); } diff --git a/modules/@angular/compiler/test/template_parser_spec.ts b/modules/@angular/compiler/test/template_parser_spec.ts index c8a9ad8db5..8f48a1a3ed 100644 --- a/modules/@angular/compiler/test/template_parser_spec.ts +++ b/modules/@angular/compiler/test/template_parser_spec.ts @@ -822,6 +822,16 @@ There is no directive with "exportAs" set to "dirA" ("
]#a="dirA">< "let-" is only supported on template elements. ("
]let-a>
"): TestComp@0:5`); }); + it('should report duplicate reference names', () => {
 + expect(() => parse('
', []))
 + .toThrowError(`Template parse errors: +Reference "#a" is defined several times ("
]#a>
"): TestComp@0:19`);
 + }); + +


 it('should not throw error when there is same reference name in different templates', () => {
 + expect(() => parse('
', [])).not.toThrowError();
 + }); + it('should assign references with empty value to components', () => { var dirA = CompileDirectiveMetadata.create({ selector: '[a]', diff --git a/modules/@angular/core/test/linker/query_integration_spec.ts b/modules/@angular/core/test/linker/query_integration_spec.ts index fc9a528394..badf0f6848 100644 --- a/modules/@angular/core/test/linker/query_integration_spec.ts +++ b/modules/@angular/core/test/linker/query_integration_spec.ts @@ -1059,11 +1059,11 @@ class NeedsContentChildWithRead { @Component({ selector: 'needs-view-children-read', - template: '
', + template: '
', directives: [TextDirective] }) class NeedsViewChildrenWithRead { - @ViewChildren('q', {read: TextDirective}) textDirChildren: QueryList; + @ViewChildren('q,w', {read: TextDirective}) textDirChildren: QueryList; @ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList; }