I'm trying to create a custom KO binding that takes an observable array, and adds a nested element to the DOM to contain a filtered subset of the elements in the observable array.
On initialisation of my custom binding I think I need to do two things. Firstly extend the binding context adding a second observable array to hold a filtered subset of the observable array that this binds to. Secondly, add add the DOM elements I want after the bound element.
Then on update of the observable array that this binding binds to, populate the observable array added to the binding context during init.
So far I have the following, non working, vastly simplified experiment.
ko.bindingHandlers.suggester = {
init: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
var innerBindingContext = bindingContext.extend(valueAccessor);
innerBindingContext.suggestions = ko.observableArray();
var ul_element = jQuery(
'<ul data-bind="foreach: suggestions">' +
'<li data-bind="text: suggestionText"></li>' +
'</ul>'
);
jQuery(element).after(ul_element);
ko.applyBindingsToDescendants(innerBindingContext, element);
return { controlsDescendantBindings: true };
},
update: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
var self = this;
jQuery.each(ko.unwrap(valueAccessor), function (index,value) {
if (/*do some filtering*/) {
bindingContext.suggestions.push({suggestionText: value});
}
});
}
};
I'm well aware the above is very wrong, but I'm bouncing from one very wrong idea to the next and really need some help.
======== EDIT ========
I've been playing around and I have something near what I'm after, but which still doesn't work.
ko.bindingHandlers.autocomplete = {
init: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
bindingContext.suggestions = ko.observableArray([{suggestionText: 'fred'}]);
var ul_element = jQuery(
'<ul data-bind="foreach: suggestions">' +
'<li data-bind="text: suggestionText"></li>' +
'</ul>'
);
jQuery(element).append(ul_element);
},
update: function ( element, valueAccessor, allBindings, viewModel, bindingContext ) {
var self = this;
bindingContext.suggestions.push({suggestionText: "another1"});
bindingContext.suggestions.push({suggestionText: "another2"});
}
};
This adds the observable array suggestions to the binding context, adds the ul/li elements to the DOM and updates them correctly. The problem is that I want to add the <ul> after the node I'm using this binding on, not within it. When I change jQuery(element).append(ul_element); to jQuery(element).after(ul_element); it doesn't work an nothing is displayed.
Additionally, I'm not sure if adding an observable directly to the binding context within my custom binding is the 'right' thing to do.