I would like to add a list of options to a page from a knockout observableArray. When there are more than a configurable number of items to be displayed, a "More options..." button (or link) should be displayed. Pressing this button should display all items and change the button text to "Less options". To make it more interesting: the button should only be displayed when there is more than 1 item that would be hidden.
The code below works (see this fiddle), but isn't there a cleaner and more generic solution (using a custom binding for example)?
<ul data-bind="foreach: options">
<li data-bind="visible: $root.showMore() || $index() < $root.showMoreCount() || $root.options().length <= $root.showMoreCount()+1, text: $data"></li>
</ul>
<a data-bind="visible: options().length-1 > showMoreCount(), text: showMore() ? 'Less options' : 'More options', click: function () { showMore(!showMore()) }"></a>
You could write a custom observable function to incorporate all your functionality:
ko.showMoreArray = function(initial) {
var observable = ko.observableArray(initial);
//observables to change behaviour
observable.limit = ko.observable(3).extend({numeric:true});
observable.showAll = ko.observable(false);
//function to toggle more/less
observable.toggleShowAll = function() {
observable.showAll(!observable.showAll());
};
//computed observable for filtered results
observable.display = ko.computed(function() {
if (observable.showAll()) { return observable(); }
return observable().slice(0,observable.limit());
}, observable);
return observable;
};
This really just wraps what you have written already, but it is reusable and leaves your HTML much neater:
<input data-bind="value: $root.orders.limit, valueUpdate: 'afterkeyup'" /><br/>
<ul data-bind="foreach: orders.display">
<li data-bind="text: $data"></li>
</ul>
<a data-bind="text: orders.showAll() ? 'Less options' : 'More options',
click: orders.toggleShowAll" href="#"></a>
I've put a working version on jsFiddle.
In the example above you need to bind to a display
property on the original array, but it will otherwise behave as the "full" array to all your code (which I think generally makes more sense). However, if you prefer that it behaves as the filtered (i.e. max 3 items) array to your code then you can achieve that in a similar way as demonstrated here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With