Skip to content

Commit

Permalink
If setDomNodeChildrenFromArrayMapping callback modified nodes, use co…
Browse files Browse the repository at this point in the history
…rrect node for next insertion. Fixes #2433
  • Loading branch information
mbest committed Jan 5, 2019
1 parent 3a5d67f commit 605c6bb
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
49 changes: 49 additions & 0 deletions spec/arrayToDomEditDetectionBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,53 @@ describe('Array to DOM node children mapping', function() {
expect(mappingInvocations.length).toEqual(0);
expect(countCallbackInvocations).toEqual(0);
});

it('Should insert nodes correctly when callback modifies node list', function() {
var array = ["A", "B"];
var mapping = function (arrayItem) {
var output1 = document.createElement("DIV");
output1.innerHTML = arrayItem + "1";
return [output1];
};
var callback = function(arrayItem, nodes) {
var output2 = document.createElement("DIV");
output2.innerHTML = arrayItem + "2";

var node = nodes[0], parent = node.parentNode;
parent.insertBefore(output2, node);
parent.removeChild(node);
nodes[0] = output2;
}

ko.utils.setDomNodeChildrenFromArrayMapping(testNode, array, mapping, null, callback);
expect(testNode.childNodes.length).toEqual(2);
expect(testNode.childNodes[0].innerHTML).toEqual("A2");
expect(testNode.childNodes[1].innerHTML).toEqual("B2");
});

it('Should insert nodes correctly when callback modifies node list when using virtual elements', function() {
// See https://github.com/knockout/knockout/issues/2433
var array = ["A", "B"];
var mapping = function (arrayItem) {
var output1 = document.createElement("DIV");
output1.innerHTML = arrayItem + "1";
return [output1];
};
var callback = function(arrayItem, nodes) {
var output2 = document.createElement("DIV");
output2.innerHTML = arrayItem + "2";

var node = nodes[0], parent = node.parentNode;
parent.insertBefore(output2, node);
parent.removeChild(node);
nodes[0] = output2;
}
testNode.innerHTML = "xxx<!--ko--><!--/ko-->";
expect(testNode.childNodes.length).toEqual(3);

ko.utils.setDomNodeChildrenFromArrayMapping(testNode.childNodes[1], array, mapping, null, callback);
expect(testNode.childNodes.length).toEqual(5);
expect(testNode.childNodes[2].innerHTML).toEqual("A2");
expect(testNode.childNodes[3].innerHTML).toEqual("B2");
});
});
3 changes: 2 additions & 1 deletion src/binding/editDetection/arrayToDomNodeChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
} else {
if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {
// Compare the provided array against the previous one
var lastArray = isFirstExecution ? [] : ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; }),
var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; }),
compareOptions = {
'dontLimitMoves': options['dontLimitMoves'],
'sparse': true
Expand Down Expand Up @@ -206,6 +206,7 @@
if (!mapData.initialized && callbackAfterAddingNodes) {
callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
mapData.initialized = true;
lastNode = mapData.mappedNodes[mapData.mappedNodes.length - 1]; // get the last node again since it may have been changed by a preprocessor
}
}

Expand Down

0 comments on commit 605c6bb

Please sign in to comment.