fix(ViewContainer) removeChild called with null parent
In view_container.js, templateElement.parentNode can be null when two template tags are nested in one another. Accessing the parent node through view.nodes[0].parentNode fixes the problem. closes #997 Closes #999
This commit is contained in:
parent
b61b8d60b7
commit
bd48c927d0
|
@ -130,7 +130,7 @@ export class ViewContainer {
|
||||||
var detachedView = this.get(atIndex);
|
var detachedView = this.get(atIndex);
|
||||||
ListWrapper.removeAt(this._views, atIndex);
|
ListWrapper.removeAt(this._views, atIndex);
|
||||||
if (isBlank(this._lightDom)) {
|
if (isBlank(this._lightDom)) {
|
||||||
ViewContainer.removeViewNodesFromParent(this.templateElement.parentNode, detachedView);
|
ViewContainer.removeViewNodes(detachedView);
|
||||||
} else {
|
} else {
|
||||||
this._lightDom.redistribute();
|
this._lightDom.redistribute();
|
||||||
}
|
}
|
||||||
|
@ -173,8 +173,11 @@ export class ViewContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeViewNodesFromParent(parent, view) {
|
static removeViewNodes(view) {
|
||||||
for (var i = view.nodes.length - 1; i >= 0; --i) {
|
var len = view.nodes.length;
|
||||||
|
if (len == 0) return;
|
||||||
|
var parent = view.nodes[0].parentNode;
|
||||||
|
for (var i = len - 1; i >= 0; --i) {
|
||||||
DOM.removeChild(parent, view.nodes[i]);
|
DOM.removeChild(parent, view.nodes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,31 @@ export function main() {
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;|c-1;|');
|
expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;|c-1;|');
|
||||||
|
|
||||||
|
component.items = [['e'], ['f', 'g']];
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('e-1;|f-2;g-2;|');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should repeat over nested arrays with no intermediate element', inject([AsyncTestCompleter], (async) => {
|
||||||
|
compileWithTemplate(
|
||||||
|
'<div><template [for] #item [of]="items">' +
|
||||||
|
'<div template="for #subitem of item">' +
|
||||||
|
'{{subitem}}-{{item.length}};' +
|
||||||
|
'</div></template></div>'
|
||||||
|
).then((pv) => {
|
||||||
|
createView(pv);
|
||||||
|
|
||||||
|
component.items = [['a', 'b'], ['c']];
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;c-1;');
|
||||||
|
|
||||||
|
component.items = [['e'], ['f', 'g']];
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('e-1;f-2;g-2;');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -116,6 +116,39 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should handle nested if correctly', inject([AsyncTestCompleter], (async) => {
|
||||||
|
compileWithTemplate('<div><template [if]="booleanCondition"><copy-me *if="nestedBooleanCondition">hello</copy-me></template></div>').then((pv) => {
|
||||||
|
createView(pv);
|
||||||
|
|
||||||
|
component.booleanCondition = false;
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||||
|
|
||||||
|
component.booleanCondition = true;
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||||
|
|
||||||
|
component.nestedBooleanCondition = false;
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||||
|
|
||||||
|
component.nestedBooleanCondition = true;
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||||
|
|
||||||
|
component.booleanCondition = false;
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||||
|
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should update several nodes with if', inject([AsyncTestCompleter], (async) => {
|
it('should update several nodes with if', inject([AsyncTestCompleter], (async) => {
|
||||||
var templateString =
|
var templateString =
|
||||||
'<div>' +
|
'<div>' +
|
||||||
|
@ -195,11 +228,13 @@ export function main() {
|
||||||
@Component({selector: 'test-cmp'})
|
@Component({selector: 'test-cmp'})
|
||||||
class TestComponent {
|
class TestComponent {
|
||||||
booleanCondition: boolean;
|
booleanCondition: boolean;
|
||||||
|
nestedBooleanCondition: boolean;
|
||||||
numberCondition: number;
|
numberCondition: number;
|
||||||
stringCondition: string;
|
stringCondition: string;
|
||||||
functionCondition: Function;
|
functionCondition: Function;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.booleanCondition = true;
|
this.booleanCondition = true;
|
||||||
|
this.nestedBooleanCondition = true;
|
||||||
this.numberCondition = 1;
|
this.numberCondition = 1;
|
||||||
this.stringCondition = "foo";
|
this.stringCondition = "foo";
|
||||||
this.functionCondition = function(s, n){
|
this.functionCondition = function(s, n){
|
||||||
|
|
Loading…
Reference in New Issue