knockout.js - data - Cómo reemplazar un elemento de índice dado en knockoutjs
knockout visible (5)
¿Cómo se reemplaza un índice dado en un Arreglo observable con otro elemento?
Tengo: ViewModel.Elements()[index]
¿Cómo puedo reemplazarlo con otro elemento?
Como dvijaz señala correctamente, la respuesta aceptada reemplaza un valor dado. Esto puede causar problemas cuando el valor dado no es único en la matriz.
En lugar de cortar la matriz y luego pegar la matriz de nuevo, hice lo siguiente, que es más legible en mi humilde opinión:
ViewModel.Elements()[index] = yourNewElement;
ViewModel.Elements.valueHasMutated();
Gracias a RP Niemeyer por señalar cómo .replace
funciona internamente.
También puede extender observableArray
para soportar esto:
ko.observableArray.fn.replaceIndex = function(index, newValue) {
this.valueWillMutate();
this()[index] = newValue;
this.valueHasMutated();
};
Lo que significa que puedes hacer lo siguiente:
var arr = ko.observableArray([1, 2, 1, 4]);
arr.replaceIndex(2, 3);
console.log(arr()); // logs [1, 2, 3, 4]
Editar el arreglo subyacente y reasignarlo me sirvió de trucos. Tuve problemas con otros enfoques.
var underlyingArray = this.someObservableArray();
// Do modifications... Swap some items...
// No one is being notified just yet...
// Reassign to observable to update everything
this.someObservableArray(underlyingArray);
La pregunta pregunta cómo reemplazar "un índice dado", en lugar de un valor dado. La respuesta aceptada funciona cuando no hay repeticiones en el Array observable, pero en caso de que haya repeticiones, entonces no siempre se comportará como se espera. Por ejemplo, supongamos que tenemos:
index = 2;
elements = ko.observableArray([9,8,9]);
y luego usamos la respuesta aceptada.
elements.replace(elements()[index], 7);
Entonces los elements
serán [7,8,9]
(porque replace
usa indexOf
, que encuentra el índice más bajo del valor dado 9
), mientras que la pregunta seguramente espera una solución que haga que los elements
sean [9,8,7]
.
Para reemplazar realmente con newElement
elemento newElement
en el index
en un elements
newElement
observable, puede usar lo siguiente.
elements(elements.slice(0, index).concat(newElement, elements.slice(index + 1)));
Algo más elegante sería agradable. Aunque IIUC es una cuestión de legibilidad más que de rendimiento.
Las flechas observables tienen un método de replace
. Esto incluye el artículo anterior y el nuevo.
Entonces, lo llamarías así:
ViewModel.Elements.replace(ViewModel.Elements()[index], yourNewElement);
Internamente, esto solo establece ese índice para su nuevo artículo y llama a valueHasMutated () para notificar a cualquier suscriptor potencial.
Ya es un poco tarde, pero me he dado cuenta de que esta pregunta aún no ha sido respondida (correctamente).
Como han dicho los otros, la primera respuesta no da el comportamiento esperado, ¡reemplazará un elemento de un observableArray
por value
y no por index
!
Las otras respuestas son demasiado complicadas y no aprovechan los nativos extendidos de Knockout.
Para reemplazar verdaderamente un valor en un index
dado de un observableArray
, debe usar el método splice()
.
var myObservable = ko.observableArray([1, 2, 3, 4]);
myObservable.splice(0, 1, 100); // Replace the value at [0] with "100"
myObservable.splice(2, 1, 300); // Replace the value at [2] with "300"
console.log(myObservable()); // [100, 2, 300, 4]
Y dado que el método splice()
se extiende mediante Knockout, notificará automáticamente cualquier dependencia, eliminando la necesidad de llamar a valueHasMutated()
.
EDIT / 14 de febrero de 2016
En caso de que necesite reemplazar múltiples valores a la vez, será mucho más rápido obtener el arreglo subyacente, realizar el reemplazo y luego notificar los cambios.
var myObservable = ko.observableArray([1, 2, 3, 4]);
var underlyingArray = myObservable();
myObservable.valueWillMutate();
for(...)
underlyingArray[i] = newValue[i];
this.valueHasMutated();