2012-04-21 37 views
20

Tengo un botón que mueve un elemento de una posición en un array observable. Lo estoy haciendo de la siguiente manera. Sin embargo, el inconveniente es que las categorías() [índice] se eliminan de la matriz, descartando cualquier manipulación de DOM (mediante la validación de jQuery en mi caso) en ese nodo.¿Cómo puedo intercambiar dos elementos en una matriz observable?

¿Hay alguna manera de intercambiar dos elementos sin usar una variable temporal para preservar el nodo DOM?

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"); 
    } 

Respuesta

36

Aquí está mi versión de moveUp que hace el canje en un solo paso:

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

Eso todavía no resuelve el problema , sin embargo, porque Knockout seguirá viendo el intercambio como un eliminar y agregar acción. Sin embargo, hay un open issue para Knockout que admite elementos móviles. Actualización: A partir de la versión 2.2.0, Knockout reconoce elementos movidos y el enlace foreach no los volverá a representar.

+0

muchas gracias, aquí está el ejemplo ** moveDown ** http: // stackoverflow.com/a/22348385/287084 – Orhaan

0

tuve un problema similar, ya que quería jQuery arrastre & gota en mis artículos. Mi solución se convirtió en utilizar plantillas knockoutjs para vincular los eventos beforeRemove y afterAdd al modelo. La clase/función de persona también es un simple modelo de vista de nocaut.

En el ejemplo siguiente, uso .draggable(), pero puede usar la validación fácilmente. Agregue su propio código para manipular el Array observable y debería estar listo para continuar.

HTML:

<div data-bind="template: {foreach:attendeesToShow, beforeRemove:hideAttendee, afterAdd:showAttendee}"> 
    <div class="person"> 
     <img src="person.jpg" alt="" /> 
     <div data-bind="text: firstName" ></div> 
     <div class="deleteimg" data-bind="click:$parent.removeAttendee" title="Remove"></div> 
    </div> 
</div> 

modelo de vista:

+0

¿Puede elaborar? Lo que intento hacer es usar botones para permitir que el usuario ordene (puede implementar arrastrar y soltar más adelante). ¿Cómo funciona antes de quitar, después de agregar preservar los elementos DOM? Los elementos DOM fueron generados por Knockout, pero fueron modificados por la validación de jQuery y pierdo los cambios al eliminar y luego reinsertar el elemento. –

+0

En mi ejemplo, simplemente vuelvo a agregar el arrastrable, en su validación de caso, cuando el elemento se vuelve a agregar al DOM. En mi caso, no es necesario preservar ninguna variable de estado (están todas en el modelo), así que funciona para mí. ¿No debería la validación ser la misma también? – jornare

0

gracias a Michael Best para su versión de moveUp

mi versión de moveDown

moveDown: function(category) { 
    var array = categories(); 
    var i = categories.indexOf(category); 
    if (i < arr.length) { 
     categories.splice(i, 2, array[i + 1], array[i]); 
    } 
} 
+0

Su versión no funciona correctamente. Reemplazar "arr.length" con "array.length - 1" hace el truco. –

5

sé esta respuesta llega un poco tarde, pero pensé que podría ser útil para otras personas que quieren una más general solución de intercambio. Puede añadir una función de intercambio de sus observableArrays así:

ko.observableArray.fn.swap = function(index1, index2) { 
    this.valueWillMutate(); 

    var temp = this()[index1]; 
    this()[index1] = this()[index2]; 
    this()[index2] = temp; 

    this.valueHasMutated(); 
} 

continuación, puede utilizar esta función para intercambiar dos elementos en una matriz dados sus índices:

myArray.swap(index1, index2); 

Para una función moveUp, usted podría a continuación, haga algo como esto:

moveUp: function(category) { 
    var i = categories.indexOf(category); 
    if (i > 0) { 
     categories.swap(i, i+1); 
    } 
} 
Cuestiones relacionadas