diff --git a/modules/angular2/src/core/linker/directive_resolver.ts b/modules/angular2/src/core/linker/directive_resolver.ts index 380cbc9f2204d..099b722d537a4 100644 --- a/modules/angular2/src/core/linker/directive_resolver.ts +++ b/modules/angular2/src/core/linker/directive_resolver.ts @@ -2,6 +2,7 @@ import {resolveForwardRef, Injectable} from 'angular2/src/core/di'; import {Type, isPresent, isBlank, stringify} from 'angular2/src/facade/lang'; import {BaseException} from 'angular2/src/facade/exceptions'; import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; + import { DirectiveMetadata, ComponentMetadata, @@ -38,7 +39,7 @@ export class DirectiveResolver { var metadata = typeMetadata.find(_isDirectiveMetadata); if (isPresent(metadata)) { var propertyMetadata = reflector.propMetadata(type); - return this._mergeWithPropertyMetadata(metadata, propertyMetadata); + return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type); } } @@ -46,7 +47,8 @@ export class DirectiveResolver { } private _mergeWithPropertyMetadata(dm: DirectiveMetadata, - propertyMetadata: {[key: string]: any[]}): DirectiveMetadata { + propertyMetadata: {[key: string]: any[]}, + directiveType: Type): DirectiveMetadata { var inputs = []; var outputs = []; var host: {[key: string]: string} = {}; @@ -100,13 +102,27 @@ export class DirectiveResolver { } }); }); - return this._merge(dm, inputs, outputs, host, queries); + return this._merge(dm, inputs, outputs, host, queries, directiveType); } private _merge(dm: DirectiveMetadata, inputs: string[], outputs: string[], - host: {[key: string]: string}, queries: {[key: string]: any}): DirectiveMetadata { + host: {[key: string]: string}, queries: {[key: string]: any}, + directiveType: Type): DirectiveMetadata { var mergedInputs = isPresent(dm.inputs) ? ListWrapper.concat(dm.inputs, inputs) : inputs; - var mergedOutputs = isPresent(dm.outputs) ? ListWrapper.concat(dm.outputs, outputs) : outputs; + + var mergedOutputs; + if (isPresent(dm.outputs)) { + dm.outputs.forEach((propName: string) => { + if (ListWrapper.contains(outputs, propName)) { + throw new BaseException( + `Output event '${propName}' defined multiple times in '${stringify(directiveType)}'`); + } + }); + mergedOutputs = ListWrapper.concat(dm.outputs, outputs); + } else { + mergedOutputs = outputs; + } + var mergedHost = isPresent(dm.host) ? StringMapWrapper.merge(dm.host, host) : host; var mergedQueries = isPresent(dm.queries) ? StringMapWrapper.merge(dm.queries, queries) : queries; diff --git a/modules/angular2/test/core/linker/directive_resolver_spec.ts b/modules/angular2/test/core/linker/directive_resolver_spec.ts index ae36e43f43bc2..2acaa353754e7 100644 --- a/modules/angular2/test/core/linker/directive_resolver_spec.ts +++ b/modules/angular2/test/core/linker/directive_resolver_spec.ts @@ -39,6 +39,12 @@ class SomeDirectiveWithOutputs { c; } + +@Directive({selector: 'someDirective', outputs: ['a']}) +class SomeDirectiveWithDuplicateOutputs { + @Output() a; +} + @Directive({selector: 'someDirective', properties: ['a']}) class SomeDirectiveWithProperties { } @@ -153,6 +159,12 @@ export function main() { var directiveMetadata = resolver.resolve(SomeDirectiveWithGetterOutputs); expect(directiveMetadata.outputs).toEqual(['a: renamed']); }); + + it('should throw if duplicate outputs', () => { + expect(() => { resolver.resolve(SomeDirectiveWithDuplicateOutputs); }) + .toThrowError( + `Output event 'a' defined multiple times in 'SomeDirectiveWithDuplicateOutputs'`); + }); }); describe('host', () => {