diff --git a/modules/angular2/src/compiler/runtime_metadata.ts b/modules/angular2/src/compiler/runtime_metadata.ts index fd4e246873..26e428a696 100644 --- a/modules/angular2/src/compiler/runtime_metadata.ts +++ b/modules/angular2/src/compiler/runtime_metadata.ts @@ -8,7 +8,6 @@ import { RegExpWrapper } from 'angular2/src/facade/lang'; import {BaseException} from 'angular2/src/facade/exceptions'; -import {MapWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import * as cpl from './directive_metadata'; import * as md from 'angular2/src/core/metadata/directives'; import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver'; @@ -77,16 +76,10 @@ export class RuntimeMetadataResolver { } } - return removeDuplicates(directives).map(type => this.getMetadata(type)); + return directives.map(type => this.getMetadata(type)); } } -function removeDuplicates(items: any[]): any[] { - let m = new Map(); - items.forEach(i => m.set(i, null)); - return MapWrapper.keys(m); -} - function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] { let directives = []; if (isPresent(platformDirectives)) { diff --git a/modules/angular2/src/compiler/template_compiler.ts b/modules/angular2/src/compiler/template_compiler.ts index 3119119570..0da1186602 100644 --- a/modules/angular2/src/compiler/template_compiler.ts +++ b/modules/angular2/src/compiler/template_compiler.ts @@ -1,6 +1,6 @@ import {IS_DART, Type, Json, isBlank, stringify} from 'angular2/src/facade/lang'; import {BaseException} from 'angular2/src/facade/exceptions'; -import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection'; +import {ListWrapper, SetWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; import { CompiledComponentTemplate, @@ -96,6 +96,7 @@ export class TemplateCompiler { private _compileComponentRuntime( cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[], compilingComponentCacheKeys: Set): CompiledComponentTemplate { + let uniqViewDirectives = removeDuplicates(viewDirectives); var compiledTemplate = this._compiledTemplateCache.get(cacheKey); var done = this._compiledTemplateDone.get(cacheKey); if (isBlank(compiledTemplate)) { @@ -109,7 +110,7 @@ export class TemplateCompiler { compilingComponentCacheKeys.add(cacheKey); done = PromiseWrapper .all([this._styleCompiler.compileComponentRuntime(compMeta.template)].concat( - viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta)))) + uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta)))) .then((stylesAndNormalizedViewDirMetas: any[]) => { var childPromises = []; var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1); @@ -175,9 +176,9 @@ export class TemplateCompiler { var compMeta = componentWithDirs.component; assertComponent(compMeta); componentMetas.push(compMeta); - this._processTemplateCodeGen(compMeta, - componentWithDirs.directives, - declarations, templateArguments); + + this._processTemplateCodeGen(compMeta, componentWithDirs.directives, declarations, + templateArguments); if (compMeta.dynamicLoadable) { var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector); componentMetas.push(hostMeta); @@ -212,9 +213,10 @@ export class TemplateCompiler { private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[], targetDeclarations: string[], targetTemplateArguments: any[][]) { + let uniqueDirectives = removeDuplicates(directives); var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template); - var parsedTemplate = - this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name); + var parsedTemplate = this._templateParser.parse(compMeta.template.template, uniqueDirectives, + compMeta.type.name); var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen( compMeta.type, compMeta.changeDetection, parsedTemplate); var commandsExpr = this._commandCompiler.compileComponentCodeGen( @@ -263,3 +265,17 @@ function addAll(source: any[], target: any[]) { function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string { return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`; } + +function removeDuplicates(items: CompileDirectiveMetadata[]): CompileDirectiveMetadata[] { + let res = []; + items.forEach(item => { + let hasMatch = + res.filter(r => r.type.name == item.type.name && r.type.moduleUrl == item.type.moduleUrl && + r.type.runtime == item.type.runtime) + .length > 0; + if (!hasMatch) { + res.push(item); + } + }); + return res; +} diff --git a/modules/angular2/test/compiler/template_compiler_spec.ts b/modules/angular2/test/compiler/template_compiler_spec.ts index ed75e99c9c..b09c0bc9ff 100644 --- a/modules/angular2/test/compiler/template_compiler_spec.ts +++ b/modules/angular2/test/compiler/template_compiler_spec.ts @@ -10,7 +10,7 @@ import { afterEach, AsyncTestCompleter, inject, - beforeEachBindings + beforeEachProviders } from 'angular2/testing_internal'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; @@ -57,7 +57,7 @@ export function main() { var compiler: TemplateCompiler; var runtimeMetadataResolver: RuntimeMetadataResolver; - beforeEachBindings(() => TEST_PROVIDERS); + beforeEachProviders(() => TEST_PROVIDERS); beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver], (_compiler, _runtimeMetadataResolver) => { compiler = _compiler; @@ -122,9 +122,18 @@ export function main() { async.done(); }); })); + + it('should dedup directives', inject([AsyncTestCompleter], (async) => { + compile([CompWithDupDirectives, TreeComp]) + .then((humanizedTemplate) => { + expect(humanizedTemplate['commands'][1]['commands'][0]).toEqual(""); + async.done(); + + }); + })); } - xdescribe('compileHostComponentRuntime', () => { + describe('compileHostComponentRuntime', () => { function compile(components: Type[]): Promise { return compiler.compileHostComponentRuntime(components[0]) .then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.template)); @@ -179,7 +188,6 @@ export function main() { }); xhr.flush(); })); - }); describe('compileTemplatesCodeGen', () => { @@ -290,6 +298,15 @@ class CompWithBindingsAndStyles { class TreeComp { } +@Component({selector: 'comp-wit-dup-tpl', moduleId: THIS_MODULE_ID}) +@View({ + template: '', + directives: [TreeComp, TreeComp], + encapsulation: ViewEncapsulation.None +}) +class CompWithDupDirectives { +} + @Component({selector: 'comp-url', moduleId: THIS_MODULE_ID}) @View({templateUrl: 'compUrl.html', encapsulation: ViewEncapsulation.None}) class CompWithTemplateUrl { @@ -349,7 +366,7 @@ export function humanizeTemplate( } class TestContext implements CompWithBindingsAndStyles, TreeComp, CompWithTemplateUrl, - CompWithEmbeddedTemplate { + CompWithEmbeddedTemplate, CompWithDupDirectives { someProp: string; }