fix(ivy): blueprints should be synced whenever they are off (#27281)
PR Close #27281
This commit is contained in:
parent
a7ba05ad82
commit
d0e8020506
|
@ -62,7 +62,6 @@ const enum BindingDirection {
|
|||
*/
|
||||
export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | null) {
|
||||
const tView = getTView();
|
||||
const parentFirstTemplatePass = getFirstTemplatePass();
|
||||
|
||||
// This needs to be set before children are processed to support recursive components
|
||||
tView.firstTemplatePass = false;
|
||||
|
@ -91,7 +90,7 @@ export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | nu
|
|||
setHostBindings(tView, viewData);
|
||||
}
|
||||
|
||||
refreshChildComponents(tView.components, parentFirstTemplatePass, rf);
|
||||
refreshChildComponents(tView.components, rf);
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,11 +146,10 @@ function refreshContentQueries(tView: TView): void {
|
|||
}
|
||||
|
||||
/** Refreshes child components in the current view. */
|
||||
function refreshChildComponents(
|
||||
components: number[] | null, parentFirstTemplatePass: boolean, rf: RenderFlags | null): void {
|
||||
function refreshChildComponents(components: number[] | null, rf: RenderFlags | null): void {
|
||||
if (components != null) {
|
||||
for (let i = 0; i < components.length; i++) {
|
||||
componentRefresh(components[i], parentFirstTemplatePass, rf);
|
||||
componentRefresh(components[i], rf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2068,16 +2066,16 @@ export function embeddedViewEnd(): void {
|
|||
* Refreshes components by entering the component view and processing its bindings, queries, etc.
|
||||
*
|
||||
* @param adjustedElementIndex Element index in LViewData[] (adjusted for HEADER_OFFSET)
|
||||
* @param rf The render flags that should be used to process this template
|
||||
*/
|
||||
export function componentRefresh<T>(
|
||||
adjustedElementIndex: number, parentFirstTemplatePass: boolean, rf: RenderFlags | null): void {
|
||||
export function componentRefresh<T>(adjustedElementIndex: number, rf: RenderFlags | null): void {
|
||||
ngDevMode && assertDataInRange(adjustedElementIndex);
|
||||
const hostView = getComponentViewByIndex(adjustedElementIndex, getViewData());
|
||||
ngDevMode && assertNodeType(getTView().data[adjustedElementIndex] as TNode, TNodeType.Element);
|
||||
|
||||
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
|
||||
if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
|
||||
parentFirstTemplatePass && syncViewWithBlueprint(hostView);
|
||||
syncViewWithBlueprint(hostView);
|
||||
detectChangesInternal(hostView, hostView[CONTEXT], rf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,9 +230,6 @@
|
|||
{
|
||||
"name": "extractPipeDef"
|
||||
},
|
||||
{
|
||||
"name": "firstTemplatePass"
|
||||
},
|
||||
{
|
||||
"name": "generateExpandoInstructionBlock"
|
||||
},
|
||||
|
@ -263,9 +260,6 @@
|
|||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
{
|
||||
"name": "getHighestElementContainer"
|
||||
},
|
||||
|
|
|
@ -782,9 +782,6 @@
|
|||
{
|
||||
"name": "findViaComponent"
|
||||
},
|
||||
{
|
||||
"name": "firstTemplatePass"
|
||||
},
|
||||
{
|
||||
"name": "flattenUnsubscriptionErrors"
|
||||
},
|
||||
|
@ -860,9 +857,6 @@
|
|||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
{
|
||||
"name": "getHighestElementContainer"
|
||||
},
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
import {NgForOfContext} from '@angular/common';
|
||||
|
||||
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
|
||||
import {AttributeMarker, defineComponent, element, templateRefExtractor} from '../../src/render3/index';
|
||||
import {bind, template, elementEnd, elementProperty, elementStart, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, text, textBinding, elementContainerStart, elementContainerEnd, reference} from '../../src/render3/instructions';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
import {getCurrentView, restoreView} from '../../src/render3/state';
|
||||
|
||||
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
|
||||
import {ComponentFixture} from './render_util';
|
||||
import {ComponentFixture, createDirective, getDirectiveOnNode} from './render_util';
|
||||
|
||||
describe('@angular/common integration', () => {
|
||||
|
||||
|
@ -131,6 +131,75 @@ describe('@angular/common integration', () => {
|
|||
.toEqual('<ul><li>0 of 3: first</li><li>1 of 3: middle</li><li>2 of 3: second</li></ul>');
|
||||
});
|
||||
|
||||
it('should instantiate directives inside directives properly in an ngFor', () => {
|
||||
let dirs: any[] = [];
|
||||
|
||||
const Dir = createDirective('dir');
|
||||
|
||||
class Comp {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: Comp,
|
||||
selectors: [['comp']],
|
||||
factory: () => new Comp(),
|
||||
consts: 2,
|
||||
vars: 0,
|
||||
template: (rf: RenderFlags, cmp: Comp) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'div', ['dir', '']);
|
||||
{ text(1, 'comp text'); }
|
||||
elementEnd();
|
||||
// testing only
|
||||
dirs.push(getDirectiveOnNode(0));
|
||||
}
|
||||
},
|
||||
directives: [Dir]
|
||||
});
|
||||
}
|
||||
|
||||
function ngForTemplate(rf: RenderFlags, ctx: NgForOfContext<string>) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
element(0, 'comp');
|
||||
}
|
||||
}
|
||||
|
||||
/** <comp *ngFor="let row of rows"></comp> */
|
||||
class MyApp {
|
||||
rows: string[] = ['first', 'second'];
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
factory: () => new MyApp(),
|
||||
selectors: [['my-app']],
|
||||
consts: 1,
|
||||
vars: 1,
|
||||
template: (rf: RenderFlags, ctx: MyApp) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
template(0, ngForTemplate, 1, 0, undefined, ['ngForOf', '']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementProperty(0, 'ngForOf', bind(ctx.rows));
|
||||
}
|
||||
},
|
||||
directives: () => [NgForOf, Comp, Dir]
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(MyApp);
|
||||
expect(fixture.html)
|
||||
.toEqual(
|
||||
'<comp><div dir="">comp text</div></comp><comp><div dir="">comp text</div></comp>');
|
||||
expect(dirs.length).toBe(2);
|
||||
expect(dirs[0] instanceof Dir).toBe(true);
|
||||
expect(dirs[1] instanceof Dir).toBe(true);
|
||||
|
||||
fixture.component.rows.push('third');
|
||||
fixture.update();
|
||||
expect(dirs.length).toBe(3);
|
||||
expect(dirs[2] instanceof Dir).toBe(true);
|
||||
expect(fixture.html)
|
||||
.toEqual(
|
||||
'<comp><div dir="">comp text</div></comp><comp><div dir="">comp text</div></comp><comp><div dir="">comp text</div></comp>');
|
||||
});
|
||||
|
||||
it('should retain parent view listeners when the NgFor destroy views', () => {
|
||||
|
||||
|
|
Loading…
Reference in New Issue