Comment pousser conditionnellement un élément dans un tableau observable?

103

Je voudrais pushun nouvel élément sur un observableArray, mais seulement si l'élément n'est pas déjà présent. Existe-t-il une fonction «find» ou un modèle recommandé pour y parvenir dans KnockoutJS?

J'ai remarqué que la removefonction sur un observableArraypeut recevoir une fonction pour passer une condition. Je veux presque la même fonctionnalité, mais ne la pousser que si la condition transmise est vraie ou non.

Jaffa
la source

Réponses:

223

Un observableArray expose une indexOffonction (wrapper to ko.utils.arrayIndexOf). Cela vous permet de faire:

if (myObservableArray.indexOf(itemToAdd) < 0) {
  myObservableArray.push(itemToAdd);
}

Si les deux ne sont pas réellement une référence au même objet et que vous souhaitez exécuter une logique de comparaison personnalisée, vous pouvez utiliser ko.utils.arrayFirstcomme:

var match = ko.utils.arrayFirst(myObservableArray(), function(item) {
    return itemToAdd.id === item.id;
});

if (!match) {
  myObservableArray.push(itemToAdd);
}
RP Niemeyer
la source
Cela fait-il une comparaison de toutes les propriétés sur itemToAdd? Je n'ai besoin que de tester une propriété Id.
jaffa
5
Cela vérifiera que les deux sont exactement le même objet. Si vous avez besoin de vérifier des propriétés individuelles, vous pouvez utiliser ko.utils.arrayFirst. J'ajouterai un échantillon à la réponse.
RP Niemeyer
4
Excellent conseil, mais j'ai dû changer itemToAdd.id === item.id en itemToAdd.id () === item.id (). J'ai posté mon code dans la réponse suivante.
Rake36
1
@ Rake36 cela dépendra du fait que vous pensez que vos identifiants d'article changeront un jour et doivent être observables.
Louis le
1
@spaceman - quel problème rencontrez-vous ===? Avez-vous un échantillon? Comparez-vous des chaînes à des nombres ou quelque chose?
RP Niemeyer
11

Merci RP. Voici un exemple d'utilisation de votre suggestion pour renvoyer la propriété 'name' via la propriété 'id' de l'objet depuis mon modèle de vue.

    self.jobroles = ko.observableArray([]);

    self.jobroleName = function (id)
    {
        var match = ko.utils.arrayFirst(self.jobroles(), function (item)
        {
            return item.id() === id();  //note the ()
        });
        if (!match)
            return 'error';
        else
            return match.name;
    };

En HTML, j'ai ce qui suit ($ parent est dû au fait que cela se trouve dans une boucle de ligne de table):

<select data-bind="visible: editing, hasfocus: editing, options: $parent.jobroles, optionsText: 'name', optionsValue: 'id', value: jobroleId, optionsCaption: '-- Select --'">
                            </select>
<span data-bind="visible: !editing(), text: $parent.jobroleName(jobroleId), click: edit"></span></td>
Râteau36
la source
0

rechercher un objet dans un ko.observableArray

function data(id,val) 
{ var self = this;
self.id = ko.observable(id);
self.valuee = ko.observable(val);  }

var o1=new data(1,"kamran");
var o2=new data(2,"paul");
var o3=new data(3,"dave");
var mysel=ko.observable();
var combo = ko.observableArray();

combo.push(o1);
combo.push(o2);
combo.push(o3);
function find()
 { 
      var ide=document.getElementById("vid").value;    
      findandset(Number(ide),mysel);
 }

function indx()
{
    var x=document.getElementById("kam").selectedIndex;
    alert(x);
}

function getsel()
{ 
    alert(mysel().valuee());
}


function findandset(id,selected)
 {  
    var obj = ko.utils.arrayFirst(combo(), function(item) {
    return  id=== item.id();
});   
     selected(obj);
 }

findandset(1,mysel);
ko.applyBindings(combo);


<select id="kam" data-bind="options: combo,
                   optionsText: 'valuee', 
                   value: mysel, 
                   optionsCaption: 'select a value'">

                   </select>
<span data-bind="text: mysel().valuee"></span>
<button onclick="getsel()">Selected</button>
<button onclick="indx">Sel Index</button>
<input id="vid" />
<button onclick="find()">Set by id</button>

http://jsfiddle.net/rathore_gee/Y4wcJ/

Kamran
la source
0

J'ajouterais "valueWillMutate ()" avant les changements et "valueHasMutated ()" après eux.

for (var i = 0; i < data.length; i++) {
    var needChange = false;
    var itemToAdd = data[i];
    var match = ko.utils.arrayFirst(MyArray(), function (item) {
        return (itemToAdd.Code === item.Code);
    });
    if (!match && !needChange) {
        MyArray.valueWillMutate();
        needChange = true;
    }
    if (!match) {
        MyArray.push(itemToAdd);
    }
}
if (needChange) {
    MyArray.valueHasMutated();
}
Pavel Babiy
la source