parent
a26965812b
commit
8b8168262d
|
@ -590,6 +590,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
||||||
|
|
||||||
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
||||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
vcRefHost.dynamicLContainerNode = lContainerNode;
|
||||||
|
lContainerNode.dynamicParent = vcRefHost;
|
||||||
|
|
||||||
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
||||||
|
|
||||||
|
@ -649,6 +650,7 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
|
||||||
(viewRef as EmbeddedViewRef<any>).attachToViewContainerRef(this);
|
(viewRef as EmbeddedViewRef<any>).attachToViewContainerRef(this);
|
||||||
|
|
||||||
insertView(this._lContainerNode, lViewNode, adjustedIdx);
|
insertView(this._lContainerNode, lViewNode, adjustedIdx);
|
||||||
|
lViewNode.dynamicParent = this._lContainerNode;
|
||||||
|
|
||||||
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
this._viewRefs.splice(adjustedIdx, 0, viewRef);
|
||||||
|
|
||||||
|
@ -672,7 +674,8 @@ class ViewContainerRef implements viewEngine_ViewContainerRef {
|
||||||
|
|
||||||
detach(index?: number): viewEngine_ViewRef|null {
|
detach(index?: number): viewEngine_ViewRef|null {
|
||||||
const adjustedIdx = this._adjustIndex(index, -1);
|
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;
|
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -318,7 +318,8 @@ export function createLNodeObject(
|
||||||
queries: queries,
|
queries: queries,
|
||||||
tNode: null !,
|
tNode: null !,
|
||||||
pNextOrParent: null,
|
pNextOrParent: null,
|
||||||
dynamicLContainerNode: null
|
dynamicLContainerNode: null,
|
||||||
|
dynamicParent: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,12 @@ export interface LNode {
|
||||||
*/
|
*/
|
||||||
// TODO(kara): Remove when removing LNodes
|
// TODO(kara): Remove when removing LNodes
|
||||||
dynamicLContainerNode: LContainerNode|null;
|
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;
|
native: RText;
|
||||||
readonly data: null;
|
readonly data: null;
|
||||||
dynamicLContainerNode: null;
|
dynamicLContainerNode: null;
|
||||||
|
dynamicParent: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Abstract node which contains root nodes of a view. */
|
/** 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: LViewNode): LContainerNode|null;
|
||||||
export function getParentLNode(node: LNode): LElementNode|LContainerNode|LViewNode|null;
|
export function getParentLNode(node: LNode): LElementNode|LContainerNode|LViewNode|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;
|
const parent = node.tNode.parent;
|
||||||
return parent ? node.view[parent.index] : node.view[HOST_NODE];
|
return parent ? node.view[parent.index] : node.view[HOST_NODE];
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,83 @@ describe('@angular/common integration', () => {
|
||||||
expect(fixture.html)
|
expect(fixture.html)
|
||||||
.toEqual('<button>Toggle List</button><ul><li>1</li><li>2</li><li>3</li></ul>');
|
.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', () => {
|
describe('ngIf', () => {
|
||||||
|
|
Loading…
Reference in New Issue