22

I have a table of data that is rendered from an object. Specifically, each row of the table is a value from the array.

I need to be able to move the object up or down in the array, depending on the button clicked.

var obj = [{
  "RuleDetailID": "11624",
  "AttributeValue": "172",
  "Value": "Account Manager",
  "IsValueRetired": "0"
}, {
  "RuleDetailID": "11626",
  "AttributeValue": "686",
  "Value": "Agent",
  "IsValueRetired": "0"
}, {
  "RuleDetailID": "11625",
  "AttributeValue": "180",
  "Value": "Analyst",
  "IsValueRetired": "0"
}, {
  "RuleDetailID": "11629",
  "AttributeValue": "807",
  "Value": "Individual Contributor",
  "IsValueRetired": "0"
}, {
  "RuleDetailID": "11627",
  "AttributeValue": "690",
  "Value": "Senior Agent",
  "IsValueRetired": "0"
}];

// Exmaple only, just rendering a table
function renderExample() {
  var table = '';
  for (var key in obj) {
    table += "<tr><td>" + obj[key].Value + "</td><td><a href=\"#\" onClick=\"move('up', " + obj[key].RuleDetailID + ")\">Move Up</a></td><td></td><td><a href=\"#\" onClick=\"move('down', " + obj[key].RuleDetailID + ")\">Move Down</a></td></tr>";
  }
  return table;
}

// Move the object in the array up or down
function move(value, positionChange) {

  // On run, move the object in the array up or down respectivly.

}
<table>
  <tbody id="example">
    <script>
      document.write(renderExample())
    </script>
  </tbody>
</table>

Can this be done with something like lodash or is it more of a manual approach? I tried by getting the index of the clicked item and then doing +1 or -1 accordingly to give me the new index. However, I wasn't sure what to do at that point since another item would already exist at that index.

How can I go about achieving this? Not looking for a jQuery approach, javascript or a library such as lodash only.

3 Answers 3

52

You can use array.splice twice, first to remove the item you want to move, and then to insert it into the new position

var data = [1,2,3,4,5];

function moveItem(from, to) {
  // remove `from` item and store it
  var f = data.splice(from, 1)[0];
  // insert stored item into position `to`
  data.splice(to, 0, f);
}

moveItem(0, 2);

console.log(data);

Sign up to request clarification or add additional context in comments.

3 Comments

How do I know the to position its going to move to? Index of from +/- 1 ?
In renderExample you have a for loop which has the key variable (the array index of each item). So you could use moveItem(key, key - 1) to move an item up, and moveItem(key, key + 1) to move it down - keep in mind to special case the first and last items of your array so they can't be moved further up/down.
'data.splice(from, 1)[0]', "1" means that one element will be removed from 'from' index . This splice retun array of removed items, in this case array of one removed item [0]. 'data.splice(to, 0, f)', when 0 items are set to delete, another parameter(s) is requited for elements which will be put in array from "to" spot.
0

You can also use an old-school swap mechanism:

function move(value, positionChange) {
  // On run, move the object in the array up or down respectivly.
  for (var i = 0; i < obj.length; i++) {
    if (obj[i].RuleDetailID == positionChange) {
      var newIndex = value === 'up' ? i - 1 : i + 1;
      if (newIndex >= obj.length || newIndex < 0) return;
      var temp = obj[i];
      obj[i] = obj[newIndex];
      obj[newIndex] = temp;
      document.getElementById('example').innerHTML = renderExample();
    }
  }
}

2 Comments

what is positionChange ??
A pythonic way of swapping items you can use here [itemList[currentIndex], itemList[otherIndex]] = [ itemList[otherIndex], itemList[currentIndex], ];
0

Instead of Array.splice() you can use Array.copyWithin(). This feels more natural, because the array's length does not have to be changed and element are only shifted once.

Here is the implementation from the top rated answer modified using Array.copyWithin():

let data = [1,2,3,4,5];

function moveItem(from, to) {
  const f = data[from];
  if (to > from) {
    // copy items after `from` until `to` one index to the left
    data.copyWithin(from, from + 1, to + 1);
  } else {
    // copy items from `to` until before `from` one index to the right
    data.copyWithin(to + 1, to, from);
  }
  // insert stored item into position `to`
  data[to] = f;
}

moveItem(2, 3);

console.log(data);

Array.copyWithin() has been supported by desktop and mobile browsers for at least 8 years, so it should be safe to use it.

Edit: It seems like using Array.splice() is much faster in this case. Here is my benchmark: https://measurethat.net/Benchmarks/Show/32906

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.