Search code examples
javascriptknockout.jsbreezedurandal

Search an observable array using Knockout, Breeze, Durandal


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.


Solution

  • 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.