Reputation: 477
I have the following observable array, which gets the data from a WebAPI using Breeze when the view is activated (at the activate() function on Durandal)
var prices = ko.observableArray();
The price class has three attributes: id, name and price.
I then have the following array:
var services = [{
active: true,
name: 'Service1',
price: getPrice('Service1')
}, {
active: true,
name: 'Service2',
price: getPrice('Service2')
}];
What the getPrice(name) function should do is get the object which has the name passed as parameter...
I want to be able to do the following on the view:
<div class="services">
<ul data-bind="foreach: services">
<li data-bind="visible: active, text: name + ' ($' + price.price + ')'"></li>
</ul>
</div>
I've searched a lot on StackOverflow and tried to do this in many ways, but haven't been able to make it work. I'm not sure if I should use ko.utils.arrayFirst(), ko.computed(), or what I should do.. I've tried many approaches without success.
Upvotes: 0
Views: 1817
Reputation: 14995
Update Figured I'd add this answer from MrYellow in comments in case anyone comes across this.
results = ko.utils.arrayMap(inputs, function(item) { return new ModelFoo(item); });
Original
You can't use that data in your view because it isn't an observable array, nor are the properties observable.
var services = ko.observableArray([{
active: ko.observable(true),
name: ko.observable('Service1'),
// Option 1
price: ko.observable(getPrice('Service1'))
}, {
active: ko.observable(true),
name: ko.observable('Service2'),
// Option 2
price: ko.computed(getPrice(name()))
}]);
This would work in your view. If you are trying to do this with Breeze then you should already have an observable unless something is going wrong, at which point we will need a bit more code.
If you want to iterate through the prices and make services do it like this -
var services = ko.observableArray();
ko.utils.arrayForEach(prices(), function (price) {
services.push(new service(price.active(), price.name(), price.price());
});
with a model somewhere like this
function service(active, name, price) {
var self = this;
self.active = ko.observable(active);
self.name = ko.observable(name);
self.price = ko.computed(getPrice(name));
}
The reason why is if you are going to create new Knockout Objects(observables) then you need to iterate through the Breeze results and make them. Use a model type like shown so you can be efficient and keep everything within scope.
Another option is that if prices() already has everything you want besides the price property, then just create a constructor method when the Breeze entities are returned to compute the price.
Upvotes: 2
Reputation: 522
I'd use the mapping plugin (http://knockoutjs.com/documentation/plugins-mapping.html) and a computed observable, where it creates the price observable rather than it being part of the original view model. See http://www.underwatergorilladome.com/how-to-use-knockouts-computed-observables-with-the-mapping-plugin/
Upvotes: -1
Reputation: 448
You can do this using straight-up JS:
var getPrice = function(name) {
var matches = prices().filter(function(x) { return x.name == name; });
if(matches.length == 0) return null;
return matches[0].price;
};
Note I do prices().filter
because it's a KO observable array and not a normal array.
Upvotes: 1