2012-04-06 120 views
28

我想显示一个可编辑的项目列表,其中的每个项目都是可编辑的(有点像可编辑的网格,有点像)。我正在使用KnockoutJS。我不能只使用一个简单的可观察数组,因为文档声明“一个可观察数组跟踪哪些对象在数组中,而不是这些对象的状态”KnockoutJS - Observable Array of Observable objects

因此,我创建了observableArray的可观察对象(使用utils。 arrayMap),并将它们绑定到视图。但是,问题是,如果我在屏幕上编辑数据,则用户在屏幕上进行的任何数据输入更改不会生效。请参阅http://jsfiddle.net/AndyThomas/E7xPM/

我在做什么错?

<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); 

}); 

回答

18

ko.utils.arrayMap不作为观测您的视图模型的属性映射,这就是为什么你没有看到他们动态更新。

如果你定义类别编号为可观察,你会看到它更新预期:

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

看到这个更新的jsfiddle:http://jsfiddle.net/tuando/E7xPM/5/

+0

完美thanksssss! – Andrew 2017-05-31 16:11:12

14

要跟进疃的答案,我需要填充我的对象基于从ASP.Net MVC控制器的服务器方法返回的数据,其中产品列表包含在视图的模型中,而下拉框的类别列表位于ViewBag中。我用下面的代码(见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); 

}); 

谢谢,抟!

+0

不错的答案:这里有更多的细节http://lostechies.com/erichexter/2012/11/29/loading-knockout-view-models-from-asp-net-mvc/ – 2012-12-03 14:40:34

1

我使用的是在调用初始化ko.utils.arrayMap

可能是你的情况矫枉过正写计算观测,但它可能会帮助别人。看到这个 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); 
    });