Reputation: 18061
Is there a way to implement the statements below using a custom binding, to eliminate the if-binding:
<div data-bind="foreach: $root.customersVM.customers">
@Html.Partial("_Customer")
<div data-bind="foreach: $root.ordersVM.orders">
<!-- ko if: customer() == $parent.id() -->
@Html.Partial("_Order")
<!-- /ko -->
</div>
</div>
Or put it in another way: Does someone know Way 2 in the answer to Knockout.js foreach: but only when comparison is true?
Upvotes: 3
Views: 11698
Reputation: 5412
How about creating another computed or function that does the filtering and that you can iterate over instead of iterating over orders?
HTML
<div data-bind="with: filteredCustomers('smith')">
<span data-bind="text: name"></span>
</div>
<div data-bind="foreach: customers">
<span data-bind="text: name"></span>
</div>
<div data-bind="foreach: filteredOrders(4)">
<span data-bind="text: id"></span>
</div>
<div data-bind="foreach: orders">
<span data-bind="text: id"></span>
</div>
<button data-bind="click: function() {customers.push({name:'Smith'});}">Add customer</button>
<button data-bind="click: function() {orders.push({id:4});}">Add order</button>
Javascript:
var vm = {
customers: ko.observableArray([
{name: 'Smith'}, {name: 'Williams'}, {name: 'Brown'}, {name: 'Miller'}
]),
orders: ko.observableArray([
{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 4}
])
};
// return first hit (unique ID)
vm.filteredCustomers = function(name) {
return ko.utils.arrayFirst(this.customers(), function(customer) {
return (customer.name.toLowerCase() === name.toLowerCase());
});
};
// return all hits
vm.filteredOrders = function(id) {
return ko.utils.arrayFilter(this.orders(), function(order) {
return (order.id === id);
});
};
ko.applyBindings(vm);
Upvotes: 12
Reputation: 22338
I think your best bet on performance would be to take the data from 2 different databases and put them together in the same viewmodel. For example, in your viewmodel in javascript, grab the customers first. Then grab the orders. Add an orders property to each customer and add an orders observablearray to it.
Your viewmodel is intended for use by the view. So its best to take the data, however it come sin, and make it work for the view. As you mention, the "if" will likely be a perf issue. Also, if you use a foreach in a function as you suggest in your comment it is needlessly looping through items when the observable arrays change. I prefer to get my viewmodel in order first, then the user interactions are fast.
2 cents :)
Upvotes: 1