parent
a26965812b
commit
8b8168262d
|
@ -590,6 +590,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
|||
|
||||
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
||||
lContainerNode.dynamicParent = vcRefHost;
|
||||
|
||||
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
||||
|
||||
|
@ -649,6 +650,7 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
|
|||
(viewRef as EmbeddedViewRef<any>).attachToViewContainerRef(this);
|
||||
|
||||
insertView(this._lContainerNode, lViewNode, adjustedIdx);
|
||||
lViewNode.dynamicParent = this._lContainerNode;
|
||||
|
||||
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
||||
|
||||
|
@ -672,7 +674,8 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
|
|||
|
||||
detach(index?: number): viewEngine_ViewRef|null {
|
||||
const adjustedIdx = this._adjustIndex(index, -1);
|
||||
detachView(this._lContainerNode, adjustedIdx);
|
||||
const lViewNode = detachView(this._lContainerNode, adjustedIdx);
|
||||
lViewNode.dynamicParent = null;
|
||||
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
|
||||
}
|
||||
|
||||
|
|
|
@ -318,7 +318,8 @@ export function createLNodeObject(
|
|||
queries: queries,
|
||||
tNode: null !,
|
||||
pNextOrParent: null,
|
||||
dynamicLContainerNode: null
|
||||
dynamicLContainerNode: null,
|
||||
dynamicParent: null
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,12 @@ export interface LNode {
|
|||
*/
|
||||
// TODO(kara): Remove when removing LNodes
|
||||
dynamicLContainerNode: LContainerNode|null;
|
||||
|
||||
/**
|
||||
* A pointer to a parent LNode created dynamically and virtually by directives requesting
|
||||
* ViewContainerRef. Applicable only to LContainerNode and LViewNode.
|
||||
*/
|
||||
dynamicParent: LElementNode|LContainerNode|LViewNode|null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,6 +135,7 @@ export interface LTextNode extends LNode {
|
|||
native: RText;
|
||||
readonly data: null;
|
||||
dynamicLContainerNode: null;
|
||||
dynamicParent: null;
|
||||
}
|
||||
|
||||
/** Abstract node which contains root nodes of a view. */
|
||||
|
|
|
@ -42,7 +42,10 @@ export function getParentLNode(node: LContainerNode | LElementNode | LTextNode |
|
|||
export function getParentLNode(node: LViewNode): LContainerNode|null;
|
||||
export function getParentLNode(node: LNode): LElementNode|LContainerNode|LViewNode|null;
|
||||
export function getParentLNode(node: LNode): LElementNode|LContainerNode|LViewNode|null {
|
||||
if (node.tNode.index === -1) return null;
|
||||
if (node.tNode.index === -1) {
|
||||
// This is a dynamic container or an embedded view inside a dynamic container.
|
||||
return node.dynamicParent;
|
||||
}
|
||||
const parent = node.tNode.parent;
|
||||
return parent ? node.view[parent.index] : node.view[HOST_NODE];
|
||||
}
|
||||
|
|
|
@ -199,6 +199,83 @@ describe('@angular/common integration', () => {
|
|||
expect(fixture.html)
|
||||
.toEqual('<button>Toggle List</button><ul><li>1</li><li>2</li><li>3</li></ul>');
|
||||
});
|
||||
|
||||
it('should support multiple levels of embedded templates', () => {
|
||||
/**
|
||||
* <ul *ngFor="let outterItem of items.">
|
||||
* <li *ngFor="let item of items">
|
||||
* <span>{{item}}</span>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
class MyApp {
|
||||
items: string[] = ['1', '2'];
|
||||
|
||||
static ngComponentDef = defineComponent({
|
||||
type: MyApp,
|
||||
factory: () => new MyApp(),
|
||||
selectors: [['my-app']],
|
||||
template: (rf: RenderFlags, myApp: MyApp) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'ul');
|
||||
{ container(1, liTemplate, null, ['ngForOf', '']); }
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementProperty(1, 'ngForOf', bind(myApp.items));
|
||||
}
|
||||
|
||||
function liTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
elementStart(0, 'li');
|
||||
{ container(1, spanTemplate, null, ['ngForOf', '']); }
|
||||
elementEnd();
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
elementProperty(1, 'ngForOf', bind(myApp.items));
|
||||
}
|
||||
}
|
||||
|
||||
function spanTemplate(rf1: RenderFlags, row: NgForOfContext<string>) {
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
elementStart(0, 'span');
|
||||
{ text(1); }
|
||||
elementEnd();
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
textBinding(1, bind(row.$implicit));
|
||||
}
|
||||
}
|
||||
},
|
||||
directives: () => [NgForOf]
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(MyApp);
|
||||
|
||||
// Change detection cycle, no model changes
|
||||
fixture.update();
|
||||
expect(fixture.html)
|
||||
.toEqual(
|
||||
'<ul><li><span>1</span><span>2</span></li><li><span>1</span><span>2</span></li></ul>');
|
||||
|
||||
// Remove the last item
|
||||
fixture.component.items.length = 1;
|
||||
fixture.update();
|
||||
expect(fixture.html).toEqual('<ul><li><span>1</span></li></ul>');
|
||||
|
||||
// Change an item
|
||||
fixture.component.items[0] = 'one';
|
||||
fixture.update();
|
||||
expect(fixture.html).toEqual('<ul><li><span>one</span></li></ul>');
|
||||
|
||||
// Add an item
|
||||
fixture.component.items.push('two');
|
||||
fixture.update();
|
||||
expect(fixture.html)
|
||||
.toEqual(
|
||||
'<ul><li><span>one</span><span>two</span></li><li><span>one</span><span>two</span></li></ul>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ngIf', () => {
|
||||
|
|
Loading…
Reference in New Issue