2012-04-06 12 views
28

Me gustaría mostrar una lista editable de elementos, cada elemento de los cuales es editable (como una cuadrícula editable, en cierto modo). Estoy usando KnockoutJS. No puedo usar simplemente una matriz observable simple porque, como la documentación dice "Un array observable rastrea qué objetos están en la matriz, no el estado de esos objetos"KnockoutJS - Matriz observable de objetos observables

Por lo tanto, he creado una matriz observable de objetos observables (usando 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); 

}); 

Respuesta

18

ko.utils.arrayMap no asigna las propiedades de su ViewModel como observables, y es por eso que no se ve actualizados dinámicamente.

Si define su CategoryId como un observable, verá que actualizar como se esperaba:

var initialData = [ 
    { 
     Name: "Television", 
     CategoryId: ko.observable("1") 
    }, 
    { 
     Name: "Melon", 
     CategoryId: ko.observable("2") 
    } 
]; 

ver este jsFiddle actualización: http://jsfiddle.net/tuando/E7xPM/5/

+0

perfect thanksssss! – Andrew

14

Para dar seguimiento a la respuesta de Tuan, que necesitaba para poblar mis objetos se basan en 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 cuadro desplegable se encuentra en el ViewBag. He utilizado el siguiente código (véase 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!

+0

Buena respuesta: hay más detalles aquí http://lostechies.com/erichexter/2012/11/29/loading-knockout-view-models-from-asp-net-mvc/ –

1

estoy usando observables calculados de escritura que se inicializan en la llamada a ko.utils.arrayMap

Puede ser una exageración, en su caso, pero podría ayudar a alguien más. Ver esto jsFiddle sample

// 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); 
    }); 
Cuestiones relacionadas