fix(ivy): trigger directive inputs for each template creation (#30870)

A directive input that doesn't use a binding is triggered during the creation phase. But this was only executed at the first template pass, and not on subsequent ones.
Now only the creation of the update instruction is executed on the first template pass, anything else is executed every time a template is created.

FW-1361 #resolve
PR Close #30870
This commit is contained in:
Olivier Combe 2019-06-05 15:38:36 +02:00 committed by Miško Hevery
parent f440bd1793
commit b4b7af86c2
2 changed files with 44 additions and 6 deletions

View File

@ -958,9 +958,7 @@ export function ɵɵi18n(index: number, message: string, subTemplateIndex?: numb
export function ɵɵi18nAttributes(index: number, values: string[]): void { export function ɵɵi18nAttributes(index: number, values: string[]): void {
const tView = getLView()[TVIEW]; const tView = getLView()[TVIEW];
ngDevMode && assertDefined(tView, `tView should be defined`); ngDevMode && assertDefined(tView, `tView should be defined`);
if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { i18nAttributesFirstPass(tView, index, values);
i18nAttributesFirstPass(tView, index, values);
}
} }
/** /**
@ -985,8 +983,10 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[])
// Even indexes are text (including bindings) // Even indexes are text (including bindings)
const hasBinding = !!value.match(BINDING_REGEXP); const hasBinding = !!value.match(BINDING_REGEXP);
if (hasBinding) { if (hasBinding) {
addAllToArray( if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes); addAllToArray(
generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes);
}
} else { } else {
const lView = getLView(); const lView = getLView();
elementAttributeInternal(previousElementIndex, attrName, value, lView); elementAttributeInternal(previousElementIndex, attrName, value, lView);
@ -1001,7 +1001,9 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[])
} }
} }
tView.data[index + HEADER_OFFSET] = updateOpCodes; if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) {
tView.data[index + HEADER_OFFSET] = updateOpCodes;
}
} }
let changeMask = 0b0; let changeMask = 0b0;

View File

@ -715,6 +715,42 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
const element = fixture.nativeElement.firstChild; const element = fixture.nativeElement.firstChild;
expect(element.title).toBe('Bonjour Angular'); expect(element.title).toBe('Bonjour Angular');
}); });
it('should apply i18n attributes during second template pass', () => {
@Directive({
selector: '[test]',
inputs: ['test'],
exportAs: 'dir',
})
class Dir {
}
@Component({
selector: 'other',
template: `<div i18n #ref="dir" test="Set" i18n-test="This is also a test"></div>`
})
class Other {
}
@Component({
selector: 'blah',
template: `
<other></other>
<other></other>
`
})
class Cmp {
}
TestBed.configureTestingModule({
declarations: [Dir, Cmp, Other],
});
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
expect(fixture.debugElement.children[0].children[0].references.ref.test).toBe('Set');
expect(fixture.debugElement.children[1].children[0].references.ref.test).toBe('Set');
});
}); });
it('should work with directives and host bindings', () => { it('should work with directives and host bindings', () => {