Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I swap two items in an observableArray?

Tags:

I have a button that moves an item one position left in an observableArray. I am doing it the following way. However, the drawback is that categories()[index] gets removed from the array, thus discarding whatever DOM manipulation (by jQuery validation in my case) on that node.

Is there a way to swap two items without using a temporary variable so as to preserve the DOM node?

    moveUp: function (category) {         var categories = viewModel.categories;         var length = categories().length;         var index = categories.indexOf(category);         var insertIndex = (index + length - 1) % length;          categories.splice(index, 1);         categories.splice(insertIndex, 0, category);         $categories.trigger("create");     } 
like image 485
Jeow Li Huan Avatar asked Apr 21 '12 10:04

Jeow Li Huan


People also ask

How do you switch two elements in an array?

To swap two array elements with this method: Create a new array, containing both elements in a particular order. Use the JavaScript array destructing syntax to unpack the values from the array into a new array that contains both elements in a reversed order.

How do you swap an element in an array?

A far better method you can use to swap array elements is destructuring, as it does the job in only one line of code. You just create a new array containing both elements in a particular order, then assign it to a new array that contains both elements in the reversed order.


2 Answers

Here's my version of moveUp that does the swap in one step:

moveUp: function(category) {     var i = categories.indexOf(category);     if (i >= 1) {         var array = categories();         categories.splice(i-1, 2, array[i], array[i-1]);     } } 

That still doesn't solve the problem, though, because Knockout will still see the swap as a delete and add action. There's an open issue for Knockout to support moving items, though. Update: As of version 2.2.0, Knockout does recognize moved items and the foreach binding won't re-render them.

like image 117
Michael Best Avatar answered Sep 24 '22 18:09

Michael Best


I know this answer comes a bit late, but I thought it might be useful to others who want a more general swap solution. You can add a swap function to your observableArrays like so:

ko.observableArray.fn.swap = function(index1, index2) {     this.valueWillMutate();      var temp = this()[index1];     this()[index1] = this()[index2];     this()[index2] = temp;      this.valueHasMutated(); } 

You can then use this function to swap two elements in an array given their indices:

myArray.swap(index1, index2); 

For a moveUp function, you could then do something like this:

moveUp: function(category) {     var i = categories.indexOf(category);     if (i > 0) {         categories.swap(i, i+1);     } } 
like image 22
David Brown Avatar answered Sep 23 '22 18:09

David Brown