Renaud
Renaud

Reputation: 2819

Behavior of NodeArray.insertBefore

By doing a JavaScript function to move order of HTML elements in a container id="ArticleContents", I had to face the following behavior by trying to move the order of elements in NodeArray with .insertBefore():

$(document).click(function(event) {
  currentItemID= event.target.id
  //... code to have articleContentSeleted=document.getElementById("DIV I want to move up or down")
  
  if (articleContentSeleted){
    childrenExistingRow=document.getElementById("ArticleContents").children;
    existingRow=document.getElementById("ArticleContents");
    var index = Array.prototype.indexOf.call(ChildrenExistingRow, ArticleContentSeleted);


    if (currentItemID =="MoveUp" && index!=0){existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index-1]);};

    if (currentItemID =="MoveDown" && index !=childrenExistingRow.length){existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index+2]);};
  }
});

It works "almost" from the first try to make the articleContentSeleted moveUP with:

if (currentItemID =="MoveUp" && index!=0){existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index-1]);};

But It requested me many time to manage to do the moveDOWN with:

if (currentItemID =="MoveDown" && index !=childrenExistingRow.length){existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index+2]);};

And now I'm curious to know why

if (currentItemID =="MoveDown" && index !=childrenExistingRow.length){existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index+1]);};

didn't do the job...

console.log(childExistingRow):

HTMLCollection(2) [textarea#Editor_Text1_0, textarea#Editor_img_1, Editor_Text1_0: textarea#Editor_Text1_0, Editor_img_1: textarea#Editor_img_1]
0: textarea#Editor_Text1_0
1: textarea#Editor_img_1
length: 2
Editor_Text1_0: textarea#Editor_Text1_0
Editor_img_1: textarea#Editor_img_1
__proto__: HTMLCollection

The behavior is the same if childExistingRow contains 2, 3 or 10 elements...

Upvotes: 0

Views: 27

Answers (1)

tevemadar
tevemadar

Reputation: 13225

insertBefore() itself seems to work well, using the xysibling properties you can avoid dealing with indices, lookups and the like:

let cnt=0;
function up(event) {
  let node = event.target.parentNode;
  let container = node.parentNode;
  if (node.previousElementSibling)
    container.insertBefore(node, node.previousElementSibling);
  log.innerText=++cnt;
}

function down(event) {
  let node = event.target.parentNode;
  let container = node.parentNode;
  if (node.nextElementSibling)
    container.insertBefore(node, node.nextElementSibling.nextElementSibling);
  log.innerText=++cnt;
}
<div>
  <div style="background:red">
    <button onclick="up(event)">&lt;</button>
      1
    <button onclick="down(event)">&gt;</button>
  </div>
  <div style="background:green">
    <button onclick="up(event)">&lt;</button>
      2
    <button onclick="down(event)">&gt;</button>
  </div>
  <div style="background:lightblue">
    <button onclick="up(event)">&lt;</button>
      3
    <button onclick="down(event)">&gt;</button>
  </div>
</div>
Clicks:<span id="log">0</span>


Maybe I understand your question after all:

existingRow.insertBefore(articleContentSeleted,childrenExistingRow[index+1]);

Inserts the row before the row it follows it, back to its current place. Remember that it's not about indices, but the items.

So it's not 1) remove X from index x, 2) all indices shift one down, 3) insert X before the element which is at index x+1 now.

But more like 1) take item Y at position x+1, 2) remove X from index x, 3) insert X before item Y. Back to its original place.

That's why the example has container.insertBefore(node, node.nextElementSibling.nextElementSibling);, also using that

referenceNode
The node before which newNode is inserted. If this is null, then newNode is inserted at the end of parentNode's child nodes.

(from docs)

Upvotes: 1

Related Questions