fix(ivy): i18n should not alloc expando slots when there is no new var (#31451)
`i18nStart` was calling `allocExpando` even if there was 0 new variable created. This created a new expando instruction with the value 0 which was later interpreted as the start of a new expando block instead of just skipping 0 instructions. FW-1417 #resolve PR Close #31451
This commit is contained in:
parent
989ebcbb62
commit
2b44be984e
|
@ -471,7 +471,9 @@ function i18nStartFirstPass(
|
|||
}
|
||||
}
|
||||
|
||||
allocExpando(viewData, i18nVarsCount);
|
||||
if (i18nVarsCount > 0) {
|
||||
allocExpando(viewData, i18nVarsCount);
|
||||
}
|
||||
|
||||
ngDevMode &&
|
||||
attachI18nOpCodesDebug(
|
||||
|
|
|
@ -11,7 +11,7 @@ import {Type} from '../../interface/type';
|
|||
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../metadata/schema';
|
||||
import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization';
|
||||
import {Sanitizer} from '../../sanitization/security';
|
||||
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertLessThan, assertNotEqual, assertNotSame} from '../../util/assert';
|
||||
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertLessThan, assertNotEqual, assertNotSame} from '../../util/assert';
|
||||
import {createNamedArrayType} from '../../util/named_array_type';
|
||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
|
||||
import {assertLView, assertPreviousIsParent} from '../assert';
|
||||
|
@ -316,24 +316,31 @@ export function assignTViewNodeToLView(
|
|||
* When elements are created dynamically after a view blueprint is created (e.g. through
|
||||
* i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future
|
||||
* template passes.
|
||||
*
|
||||
* @param view The LView containing the blueprint to adjust
|
||||
* @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0
|
||||
*/
|
||||
export function allocExpando(view: LView, numSlotsToAlloc: number) {
|
||||
const tView = view[TVIEW];
|
||||
if (tView.firstTemplatePass) {
|
||||
for (let i = 0; i < numSlotsToAlloc; i++) {
|
||||
tView.blueprint.push(null);
|
||||
tView.data.push(null);
|
||||
view.push(null);
|
||||
}
|
||||
ngDevMode && assertGreaterThan(
|
||||
numSlotsToAlloc, 0, 'The number of slots to alloc should be greater than 0');
|
||||
if (numSlotsToAlloc > 0) {
|
||||
const tView = view[TVIEW];
|
||||
if (tView.firstTemplatePass) {
|
||||
for (let i = 0; i < numSlotsToAlloc; i++) {
|
||||
tView.blueprint.push(null);
|
||||
tView.data.push(null);
|
||||
view.push(null);
|
||||
}
|
||||
|
||||
// We should only increment the expando start index if there aren't already directives
|
||||
// and injectors saved in the "expando" section
|
||||
if (!tView.expandoInstructions) {
|
||||
tView.expandoStartIndex += numSlotsToAlloc;
|
||||
} else {
|
||||
// Since we're adding the dynamic nodes into the expando section, we need to let the host
|
||||
// bindings know that they should skip x slots
|
||||
tView.expandoInstructions.push(numSlotsToAlloc);
|
||||
// We should only increment the expando start index if there aren't already directives
|
||||
// and injectors saved in the "expando" section
|
||||
if (!tView.expandoInstructions) {
|
||||
tView.expandoStartIndex += numSlotsToAlloc;
|
||||
} else {
|
||||
// Since we're adding the dynamic nodes into the expando section, we need to let the host
|
||||
// bindings know that they should skip x slots
|
||||
tView.expandoInstructions.push(numSlotsToAlloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1463,6 +1463,30 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
.toEqual(`<div-query>Contenu<!--ng-container--></div-query>`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not alloc expando slots when there is no new variable to create', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div dialog i18n>
|
||||
<div *ngIf="data">
|
||||
Some content
|
||||
</div>
|
||||
</div>
|
||||
<button [close]="true">Button label</button>
|
||||
`
|
||||
})
|
||||
class ContentElementDialog {
|
||||
data = false;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [DialogDir, CloseBtn, ContentElementDialog]});
|
||||
|
||||
const fixture = TestBed.createComponent(ContentElementDialog);
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div dialog=""><!--bindings={
|
||||
"ng-reflect-ng-if": "false"
|
||||
}--></div><button ng-reflect-dialog-result="true" title="Close dialog">Button label</button>`);
|
||||
});
|
||||
});
|
||||
|
||||
function initWithTemplate(compType: Type<any>, template: string) {
|
||||
|
@ -1491,3 +1515,13 @@ class DirectiveWithTplRef {
|
|||
class UppercasePipe implements PipeTransform {
|
||||
transform(value: string) { return value.toUpperCase(); }
|
||||
}
|
||||
|
||||
@Directive({selector: `[dialog]`})
|
||||
export class DialogDir {
|
||||
}
|
||||
|
||||
@Directive({selector: `button[close]`, host: {'[title]': 'name'}})
|
||||
export class CloseBtn {
|
||||
@Input('close') dialogResult: any;
|
||||
name: string = 'Close dialog';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue