knockout.js - observablearray - KnockoutJS-Matriz observable de objetos observables
ko observablearray clear (3)
Me gustaría mostrar una lista editable de elementos, cada uno de los cuales es editable (como una cuadrícula editable, en cierto modo). Estoy usando KnockoutJS. No puedo usar simplemente una matriz de observación simple porque, como dice la documentación, "Un array observable rastrea qué objetos están en la matriz, no el estado de esos objetos".
Por lo tanto, he creado una matriz observable de objetos observables (utilizando utils.arrayMap) y los vinculé a la vista. Sin embargo, el problema es que si edito los datos en la pantalla, los cambios de entrada de datos que realice el usuario en la pantalla no parecen tener efecto. Ver http://jsfiddle.net/AndyThomas/E7xPM/
¿Qué estoy haciendo mal?
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.0.0/knockout-min.js" type="text/javascript"></script>
<table>
<tbody data-bind="template: { name:''productListJavascriptTemplate'', foreach: products}">
</tbody>
</table>
<script type="text/html" id="productListJavascriptTemplate">
<tr>
<td>Name: <input data-bind="value: Name"/></td>
<td>Name: <span data-bind="text: Name"/></td>
<td><select data-bind="options: this.viewModel.categories,
optionsText: ''Name'', optionsValue: ''Id'', value: CategoryId,
optionsCaption: ''Please select...''"></select></td>
<td>CategoryId: <input data-bind="value: CategoryId"/></td>
</tr>
</script>
var categoryList= [
{
Name: "Electronics",
Id: "1"},
{
Name: "Groceries",
Id: "2"}
];
var initialData= [
{
Name: "Television",
CategoryId: "1"},
{
Name: "Melon",
CategoryId: "2"}
];
var viewModel = {
products: ko.observableArray(
ko.utils.arrayMap(initialData, function(product) {
return ko.observable(product);
})),
categories: ko.observableArray(categoryList)
};
$(function() {
ko.applyBindings(viewModel);
});
1.
Estoy usando observables computables escribibles que se inicializan en la llamada a ko.utils.arrayMap
Puede ser una exageración en su caso, pero podría ayudar a otra persona. Ver esta muestra jsFiddle
// Writeable computed observables
function Customer(id, firstName, lastName, preferred) {
var self = this;
self.id = id;
self.firstName = firstName;
self.lastName = lastName;
// Non-Writeable computed observable
self.fullName = ko.computed(function() {
var fn = self.firstName;
var ln = self.lastName;
return ln ? fn + '' '' + ln : fn;
}, self);
self.preferred = ko.observable(preferred);
// Writeable computed observable
self.isPreferred = ko.computed({
read: function() {
var preferredStr = self.preferred() || '''';
var isPreferredComputed = preferredStr.toUpperCase();
return (isPreferredComputed === ''Y'') ? true : false;
},
write: function(value) {
self.preferred( (!value) ? '''' : (value ? ''Y'' : ''''));
},
owner: self
});
}
var mappedData = ko.utils.arrayMap(dataFromServer, function(customer) {
return new Customer(customer.id, customer.firstName, customer.lastName, customer.preferred);
});
Para dar seguimiento a la respuesta de Tuan, necesitaba llenar mis objetos en base a datos devueltos por un método de servidor desde un controlador ASP.Net MVC, donde la lista de Productos está contenida en el Modelo de la vista y la lista de categorías para el menú desplegable la caja está en el ViewBag. Utilicé el siguiente código (consulte también http://www.knockmeout.net/2011/04/utility-functions-in-knockoutjs.html ):
var initialData = @Html.Raw( new JavaScriptSerializer().Serialize(Model));
var categoryList = @Html.Raw( new JavaScriptSerializer().Serialize(ViewBag.CategoryList));
var ObservableProduct = function(name, description, categoryId) {
this.Name = ko.observable(name);
this.Description = ko.observable(description);
this.CategoryId = ko.observable(categoryId);
};
var viewModel = {
products: ko.observableArray(ko.utils.arrayMap(initialData, function(product) {
return new ObservableProduct(product.Name, product.Description, product.CategoryId);
})),
categories: ko.observableArray(categoryList)
};
$(function() {
ko.applyBindings(viewModel);
});
Gracias, Tuan!
ko.utils.arrayMap no correlaciona las propiedades de su viewmodel como observables, y es por eso que no las ve dinámicamente.
Si define su CategoryId como observable, la verá actualizarse como se espera:
var initialData = [
{
Name: "Television",
CategoryId: ko.observable("1")
},
{
Name: "Melon",
CategoryId: ko.observable("2")
}
];
Vea este jsfiddle actualizado: http://jsfiddle.net/tuando/E7xPM/5/