简体   繁体   中英

KnockoutJS how to implement a computed observable for each item of an array?

I need to have a computed observable for each element of an array. The resolution of this computed observable needs to rely on other properties existing in the context of each array element.

Please check the following example case:

This is the result of a KnockoutJS foreach binding to a nested array, having a group = category, and items nested in each category.

In my scenario, and initial array has "plain" properties in its elements, as if retrieved from a backend, to later be mapped into another array with the same structure, but with the quantity property deliberately set to a knockout observable. In this mapping process where I set quantity to be a knockout observable, I also need to set another computed observable property to represent the item total (price property x quantity property). This item total computed observable has to happen for each element of the array, and has to depend on the content of price and quantity property in the context of each array element.

Please check the following screen shot, imagine a bar menu where quantity is entered on the input tag bound to observable array elements, and upon changing each quantity, a computed observable bound to a td tag should reflect the item total calculation.

在此处输入图片说明

Please also check the JS Fiddle for this

As you will notice in the JS Fiddle, this part in the array mapping function to implement the totalComputed property is obviously wrong, it does not work.

totalComputed: ko.computed(function() {
          return element.items[indexInArrayItems].quantity * element.items[indexInArrayItems].price;
        })

Can you help, preferrably making my JS Fiddle work?

You need to take advantage of knockout's power by creating observable variables and observableArray then have dependencies in your computed function in order to have your computed gets updated automatically every time any of its dependencies change.

Here is based on your JS Fiddle example : https://jsfiddle.net/rnhkv840/22/

var MainViewModel = function(){
 var self = this;
 self.dataSource = ko.observableArray([]);
 //probably inside your ajax success
 self.dataSource($.map(dataFromBackend, function (item) {
   return new CategoryViewModel(item);
  }));
}

var CategoryViewModel = function(data){
  var self = this;
  self.Items = ko.observableArray($.map(data.items, function (item) {
    return new ItemViewModel(item);
  }));
  self.category = ko.observable(data.category);
}

var ItemViewModel = function(data){
  var self = this;
  self.description = ko.observable(data.description);
  self.price = ko.observable(data.price);
  self.quantity = ko.observable(data.quantity);
  self.totalComputed = ko.computed(function () {
      return self.price() * self.quantity();
  });
}
var vm = new MainViewModel();
ko.applyBindings(vm);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM