2016-05-24 4 views
1

Gibt es eine Möglichkeit, ein Array-Element als Wert einer Eingabe oder Auswahl zu binden?Datenbindung eines Array-Elements als Wert mithilfe von knockout

So etwas ...

var ViewModel = function() { 
 
    var self = this; 
 

 
    self.array = ko.observableArray([undefined, undefined, undefined]); 
 

 
    self.text = ko.computed(function() { 
 
    return self.array()[0] + self.array()[1] + self.array()[2]; 
 
    }); 
 
} 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<input data-bind="value: $root.array[0]" /> 
 
<input data-bind="value: $root.array[1]" /> 
 
<input data-bind="value: $root.array[2]" /> 
 
<p data-bind="text: $root.text"></p>

EDIT

Sorry, Jungs, ich bin wirklich schrecklich Fragen zu machen, aber mein Problem ist ein wenig komplizierter Meine tatsächlichen Einträge sind selects, die ein Filter eines Arrays und die ausgewählten Werte sind. dies wie:

var ViewModel = function() { 
 
    var self = this; 
 
    self.family = ko.mapping.fromJS(data.family); 
 

 
    self.array = ko.observableArray([ko.observable(undefined), ko.observable(undefined), ko.observable(undefined)]); 
 

 
    self.filterFamily1 = function() { 
 
    return self.family().filter(function(i) { 
 
     return i.parent() == null; 
 
    }); 
 

 
    } 
 
    self.filterFamily2 = ko.computed(function() { 
 
    return ko.utils.arrayFilter(self.family, function(i) { 
 
     return i.parent() === self.array()[0]().name(); 
 
    }); 
 

 
    }); 
 
    self.filterFamily3 = ko.computed(function() { 
 
    return ko.utils.arrayFilter(self.family, function(i) { 
 
     return i.parent() === self.array()[1]().name(); 
 
    }); 
 

 
    }) 
 

 
} 
 

 
var data = { 
 
    family: [{ 
 
    name: "John", 
 
    parent: null 
 
    }, { 
 
    name: "Mary", 
 
    parent: null 
 
    }, { 
 
    name: "Erick", 
 
    parent: "John" 
 
    }, { 
 
    name: "Paul", 
 
    parent: "John" 
 
    }, { 
 
    name: "Marshall", 
 
    parent: "Mary" 
 
    }, { 
 
    name: "Ross", 
 
    parent: "Paul" 
 
    }] 
 
}; 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> 
 

 
<select data-bind="options: $root.filterFamily1(),optionsText: 'name', value: $root.array()[0]"></select> 
 
<select data-bind="options: $root.filterFamily2(),optionsText: 'name', value: $root.array()[1]"></select> 
 
<select data-bind="options: $root.filterFamily3(),optionsText: 'name', value: $root.array()[2]"></select>

aber die Antworten waren richtig für das Problem, das ich vor beschreiben.

Antwort

2

Da Ihre Frage sehr verändert, ich bin eine neue Antwort zu veröffentlichen:

Ihre Schnipsel Konsole Fehler hatte: Ihre ursprünglich ausgewählten Werte wurden nicht festgelegt, noch haben Sie überprüfen für undefiniert. Fügen Sie diese Überprüfungen ein und alles funktioniert.

Beachten Sie, dass Sie auf jeden Fall die Lesbarkeit verbessern und wiederkehrende Codeabschnitte umgestalten können.

var ViewModel = function() { 
 
    var self = this; 
 
    self.family = ko.mapping.fromJS(data.family); 
 

 

 

 

 
    self.filterFamily1 = ko.computed(function() { 
 
    return self.family().filter(function(i) { 
 
     return i.parent() === null; 
 
    }); 
 

 
    }); 
 

 
    self.array = ko.observableArray([ 
 
    ko.observable(self.filterFamily1()[0]), 
 
    ko.observable(undefined), 
 
    ko.observable(undefined) 
 
    ]); 
 

 
    self.filterFamily2 = ko.computed(function() { 
 
    return self.family().filter(function(i) { 
 
     return self.array()[0]() && i.parent() === self.array()[0]().name(); 
 
    }); 
 

 
    }); 
 
    self.filterFamily3 = ko.computed(function() { 
 
    return self.family().filter(function(i) { 
 
     return self.array()[1]() && i.parent() === self.array()[1]().name(); 
 
    }); 
 

 
    }) 
 

 
} 
 

 
var data = { 
 
    family: [{ 
 
    name: "John", 
 
    parent: null 
 
    }, { 
 
    name: "Mary", 
 
    parent: null 
 
    }, { 
 
    name: "Erick", 
 
    parent: "John" 
 
    }, { 
 
    name: "Paul", 
 
    parent: "John" 
 
    }, { 
 
    name: "Marshall", 
 
    parent: "Mary" 
 
    }, { 
 
    name: "Ross", 
 
    parent: "Paul" 
 
    }] 
 
}; 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> 
 

 
<select data-bind="options: $root.filterFamily1(),optionsText: 'name', value: $root.array()[0]"></select> 
 
<select data-bind="options: $root.filterFamily2(),optionsText: 'name', value: $root.array()[1]"></select> 
 
<select data-bind="options: $root.filterFamily3(),optionsText: 'name', value: $root.array()[2]"></select>

+0

Vielen Dank, es funktioniert. – Guto

2

Wenn Sie auf das Array nach Index zugreifen möchten, müssen Sie das Observable zuerst mit () auswerten.

Wenn die Bindung value zweiseitig arbeiten soll (z. B. nicht nur initialisieren, sondern auch die Werte in Ihrem Ansichtsmodell nach einer Änderung aktualisieren), müssen Sie sie an ko.observable Variablen binden.

Weitere Verbesserungen:

Wenn Sie alle Werte miteinander verbinden möchten, können Sie reduce oder eine Kombination aus map und join die Saiten anhängen nutzen könnten.

EDIT: Ich lag falsch hier! Sie können auch eine foreach Bindung verwenden und $data verwenden, um auf den aktuellen Wert zu verweisen, wenn Sie Eingaben für alle Werte Ihres Arrays benötigen.

Eigentlich können Sie keine Zweiwege-Bindung mit dem Schlüsselwort $data erstellen. Sie können, wenn Sie die $index beobachtbar verwenden.

Referenz: https://github.com/knockout/knockout/issues/708

var ViewModel = function() { 
 
    var self = this; 
 

 
    self.array = ko.observableArray([ko.observable("a"), ko.observable("b"), ko.observable("c")]); 
 

 
    self.text = ko.computed(function() { 
 
    return self.array()[0]() + self.array()[1]() + self.array()[2](); 
 
    }); 
 

 
    self.reducedText = ko.computed(function() { 
 
    return self.array() 
 
     .reduce(function(prev, curr) { 
 
     return prev + curr(); 
 
     }, ""); 
 

 
    }); 
 
}; 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<input data-bind="value: array()[0]" /> 
 
<input data-bind="value: array()[1]" /> 
 
<input data-bind="value: array()[2]" /> 
 
<p data-bind="text: text"></p> 
 

 
<!-- EDIT: this does not create a two way binding 
 
<div data-bind="foreach: array"> 
 
    <input data-bind="value: $data" /> 
 
</div> 
 
--> 
 

 
<!-- EDIT: this does work --> 
 
<div data-bind="foreach: array"> 
 
    <input data-bind="value: $parent.array()[$index()]" /> 
 
</div> 
 

 
<p data-bind="text: reducedText"></p>

+0

wie ich oben sagte, die Lösung funktioniert gut, aber mein eigentliches Problem ist anders, ich dachte, dass, wenn es zu für die Eingänge vielleicht funktioniert für wählt funktioniert. – Guto

+0

Ich habe eine zweite Antwort gepostet, da das enthaltene Snippet nach dem Update sich sehr verändert hat ... Sie finden es hier: http://StackOverflow.com/a/37416047/3297291 – user3297291

3

Yessir, gibt es sicherlich. Aber:

  1. Die Einzelteile müssen sich observable s sein.
  2. Sie sollten die self.array Funktion ausführen, bevor Sie an eines ihrer Elemente binden.

Hier ist ein Beispiel:

var ViewModel = function() { 
 
    var self = this; 
 

 
    self.array = ko.observableArray([ko.observable(""), ko.observable(""), ko.observable("")]); 
 

 
    self.text = ko.computed(function() { 
 
    return self.array()[0]() + self.array()[1]() + self.array()[2](); 
 
    }); 
 
} 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<input data-bind="value: $root.array()[0]" /> 
 
<input data-bind="value: $root.array()[1]" /> 
 
<input data-bind="value: $root.array()[2]" /> 
 
<p data-bind="text: $root.text"></p>

Doch warum nicht die foreach Bindung und einige andere nette Verbesserungen nutzen?

var ViewModel = function() { 
 
    var self = this; 
 

 
    self.array = ko.observableArray([ 
 
    { txt: ko.observable("a") }, 
 
    { txt: ko.observable("b") }, 
 
    { txt: ko.observable("c") }, 
 
    { txt: ko.observable("d") } 
 
    ]); 
 

 
    self.text = ko.computed(function() { 
 
    return self.array().map(function(obs) { return obs.txt(); }).join(""); 
 
    }); 
 
} 
 

 
var viewModel = new ViewModel(); 
 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> 
 

 
<!-- ko foreach: array --> 
 
<input data-bind="textInput: txt"> 
 
<!-- /ko --> 
 
<p data-bind="text: text"></p>

+0

Wie ich oben sagte, funktioniert die Lösung gut, aber mein wirkliches Problem ist anders, ich dachte, dass, wenn es für Eingaben funktioniert, auch für selects funktioniert. – Guto