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 parison is true?
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 parison is true?
Share Improve this question edited May 23, 2017 at 12:25 CommunityBot 11 silver badge asked Apr 1, 2012 at 20:59 mhumhu 18.1k10 gold badges65 silver badges94 bronze badges 6- try knockoutjs./documentation/custom-bindings.html , it's will work for you. – Chinook Commented Apr 1, 2012 at 21:01
- @Sergio: if has a number of drawbacks, which I'm trying to eliminate. See: link – mhu Commented Apr 1, 2012 at 21:05
- @user1252580: Been there, but it didn't answer my question – mhu Commented Apr 1, 2012 at 21:06
- 1 I'm confused on why you would have customers that you are looping through, then the orders are for any customer. Why not get customers and their orders in the same json, then its a non issue? – John Papa Commented Apr 1, 2012 at 21:41
-
@John: The example is of course simplified. It involves separate database tables with separate ViewModels. I'm think a custom binding, say
foreachFiltered
, would be the best answer to my question. – mhu Commented Apr 1, 2012 at 22:00
2 Answers
Reset to default 12How about creating another puted 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);
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 e 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 ment 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 :)