fix(compiler): don't trigger duplicated directives

Fixes #2756
Closes #2568
This commit is contained in:
Pawel Kozlowski 2015-06-16 20:16:08 +02:00 committed by Tobias Bosch
parent 0b50258814
commit 0598226e24
2 changed files with 56 additions and 2 deletions

View File

@ -153,8 +153,8 @@ export class Compiler {
} }
} }
var boundDirectives = var boundDirectives = this._removeDuplicatedDirectives(
ListWrapper.map(directives, (directive) => this._bindDirective(directive)); ListWrapper.map(directives, (directive) => this._bindDirective(directive)));
var renderTemplate = this._buildRenderTemplate(component, view, boundDirectives); var renderTemplate = this._buildRenderTemplate(component, view, boundDirectives);
pvPromise = pvPromise =
@ -167,6 +167,12 @@ export class Compiler {
return pvPromise; return pvPromise;
} }
private _removeDuplicatedDirectives(directives: List<DirectiveBinding>): List<DirectiveBinding> {
var directivesMap: Map<number, DirectiveBinding> = new Map();
directives.forEach((dirBinding) => { directivesMap.set(dirBinding.key.id, dirBinding); });
return MapWrapper.values(directivesMap);
}
private _compileNestedProtoViews(componentBinding, renderPv, directives): Promise<AppProtoView>| private _compileNestedProtoViews(componentBinding, renderPv, directives): Promise<AppProtoView>|
AppProtoView { AppProtoView {
var protoViews = var protoViews =

View File

@ -299,6 +299,40 @@ export function main() {
.then((rootTC) => { async.done(); }); .then((rootTC) => { async.done(); });
})); }));
it('should execute a given directive once, even if specified multiple times',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new viewAnn.View({
template: '<p no-duplicate></p>',
directives: [
DuplicateDir,
DuplicateDir,
[DuplicateDir, [DuplicateDir, bind(DuplicateDir).toClass(DuplicateDir)]]
]
}))
.createAsync(MyComp)
.then((rootTC) => {
expect(rootTC.nativeElement).toHaveText('noduplicate');
async.done();
});
}));
it('should use the last directive binding per directive',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new viewAnn.View({
template: '<p no-duplicate></p>',
directives: [
bind(DuplicateDir)
.toClass(DuplicateDir),
bind(DuplicateDir).toClass(OtherDuplicateDir)
]
}))
.createAsync(MyComp)
.then((rootTC) => {
expect(rootTC.nativeElement).toHaveText('othernoduplicate');
async.done();
});
}));
it('should support directives where a selector matches property binding', it('should support directives where a selector matches property binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new viewAnn.View( tcb.overrideView(MyComp, new viewAnn.View(
@ -1805,3 +1839,17 @@ class ExportDir {
@Component({selector: 'comp'}) @Component({selector: 'comp'})
class ComponentWithoutView { class ComponentWithoutView {
} }
@Directive({selector: '[no-duplicate]'})
class DuplicateDir {
constructor(renderer: DomRenderer, private elRef: ElementRef) {
DOM.setText(elRef.nativeElement, DOM.getText(elRef.nativeElement) + 'noduplicate');
}
}
@Directive({selector: '[no-duplicate]'})
class OtherDuplicateDir {
constructor(renderer: DomRenderer, private elRef: ElementRef) {
DOM.setText(elRef.nativeElement, DOM.getText(elRef.nativeElement) + 'othernoduplicate');
}
}