web-dev-qa-db-fra.com

Actualiser observableArray lorsque les éléments ne sont pas observables

Fondamentalement, j'ai un observableArray et les valeurs pour chaque élément ne sont pas observables. Cela signifie que lorsque je modifie une valeur d'élément, l'interface utilisateur dans une boucle foreach de l'observableArray n'est pas mise à jour en conséquence.

Cela signifie un changement massif si je dois les définir sur observable. Y a-t-il moyen de rafraîchir manuellement l'interface utilisateur ou observableArray foreach?

29
user1166905

Oui, vous pouvez appeler la fonction valueHasMutated pour votre tableau:

yourArray.valueHasMutated();

EDIT: Si le premier n’a pas aidé, vous pouvez effectuer un rafraîchissement «en sale»:

self.refresh = function(){
    var data = self.array().slice(0);
    self.array([]);
    self.array(data);
};

Voici le violon en marche: http://jsfiddle.net/vyshniakov/FuEy6/2/

54
Artem Vyshniakov

Lorsque vous avez un tableau observable avec des éléments non observables et que certaines propriétés de l'un des éléments du tableau changent, si vous souhaitez actualiser uniquement cet élément, vous pouvez utiliser indexOf et splice, comme ceci:

var changedIdx = obsArray.indexOf(changedItem);
obsArray.splice(changedIdx , 1); // removes the item from the array
obsArray.splice(changedIdx , 0, changedItem); // adds it back

Ce que cela fait, c'est de rechercher l'élément dans le tableau, de le supprimer et de le réinsérer. Lorsqu'il est réinséré, l'élément est à nouveau lié aux nouvelles valeurs.

Si vous aimez cette solution, vous pouvez étendre les fonctionnalités de tous les tableaux observables ko, comme ceci:

ko.observableArray.fn.refresh = function (item) {
    var index = this['indexOf'](item);
    if (index >= 0) {
        this.splice(index, 1);
        this.splice(index, 0, item);
    }
}

Ensuite, lorsque vous modifiez un élément d'un tableau, vous devez simplement effectuer cet appel:

obsArray.refresh(changedItem);

Si votre tableau contient de nombreux éléments, vous obtiendrez une performance améliorée par rapport à la régénération dirty par Artem Vyshniakov, qui met à jour les liaisons pour tous les éléments du tableau, et pas uniquement pour celui modifié.

Remarque: la valueHasMutated, en plus d'être non documentée (et pour usage interne, je suppose), vérifie uniquement si le tableau a été modifié, et non pas si les éléments non observables du tableau ont été modifiés. C'est à dire. il ne détecte que si vous avez ajouté des éléments au tableau, supprimé des éléments du tableau, modifié des éléments du tableau avec de nouveaux éléments différents ou modifié l'ordre des éléments. Mais il ne vérifie pas si les éléments eux-mêmes ont changé

19
JotaBe

J'ai fini par utiliser l'approche sale par le haut mais j'ai fait en sorte que tous mes tableaux observables aient cette fonctionnalité.

ko.observableArray.fn.refresh = function () {
        var data = this().slice(0);
        this([]);
        this(data);
    };

La valeur HasMutated n'a pas fonctionné pour moi. Son genre de boiteux toute la liste doit être mise à jour. Ou dans mon cas, trouvez un moyen d'étendre le plug-in ko mapping pour remplir les tableaux observables d'objets observables.

5
MrB

J'ai trouvé une solution simple en remplaçant l'objet entier dans le tableau.

Dans cet exemple, le paramètre ix est l'indice, oLine est l'objet mis à jour et oVM.objProps.lines contient le tableau. La solution a fonctionné comme un champion.

/* This contortion causes the computed function to fire because
 * we have replaced the entire line object.
 */
function forceRefresh(ix,oLine) {
  var oVM = pme.getVM();
  oLine = JSON.parse(JSON.stringify(oLine));
  oVM.oObjProp.lines[ix] = oLine;
}
0
Steve Pritchard

J'utilise Knockout avec deferUpdates et la solution de JotaBe nécessite une mise à jour.

Il semble que Knockout détecte, lors de la suppression/ajout, qu'il s'agit du même élément et ne rafraîchit donc pas le tableau.

J'ai adopté la solution suivante:

ko.observableArray.fn.refresh = function (item, index) {
    if (index==null) index = this['indexOf'](item);
    if (index >= 0) {
        this.splice(index, 1, ko.utils.extend({}, item)) // create new item
        //this.splice(index, 1);
        //this.splice(index, 0, item);
    }
}

et il actualise le tableau correctement! :-)

Note J'ai ajouté un deuxième argument pour rafraîchir la fonction, pour spécifier l'index quand index est donné, pour éviter l'exécution d'indexOf.

0
RFex