The code you're showing hardly resembles the correct implementation of a custom binder.
Several hints:
- you should use the custom binding in the root element
- the custom binding should take care of building, and, if possible, removing the carousel API from the element (using slick's
destroy
or unslick
) if the element is disposed of by ko
- the custom binder should be able to update the elements inside the carousel
- it would be interesting to use an additional
slickOptions
binding to pass additional objects to the slick initialization
The basic structure of a custom binding is explained here. See the code template:
ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called once when the binding is first applied to an element,
// and again whenever any observables/computeds that are accessed change
// Update the DOM element based on the supplied values here.
}
};
As explained, the init
is responsible of initializing the caroulse, and the update
is responsible of updating the content of the carousel when the array changes. R P Niemeyer makes an in depth explanation of custom binding here: Another Look at Custom Bindings for KnockoutJS.
If you implement it correctly, your HTML code should look something like this:
<div data-bind="slick: imagesArray, slickOptions: additionalOptions>
</div>
On the init
, your custom binding should create the elements based on the imagesArray
, and call the slick initialization, using the additionalOptions
if present, and register the slick destruction when the element is disposed of by ko. In the update you should modify the inner elements and possible reapply slick. You should also review slick's API.
This fiddle shows a partial implementation, but more complete that the current the floowing snippet:
var imageUrls = [];
var i = 1;
for (i=1;i<=10;i++)
imageUrls.push('http://lorempixel.com/400/200/animals/'+i);
ko.bindingHandlers.slick = {
init: function(element, valueAccessor, allBindingsAccessor) {
// Clears the div
$(element).empty();
// Creates the inner divs with images
var images = ko.unwrap(valueAccessor());
if (images) {
images.forEach(function(imgUrl) {
$div = $('<div>');
$image = $('<img>');
$image.attr('src',imgUrl);
$div.append($image);
$(element).append($div)
});
}
// try to recover slickOptions
var options = allBindingsAccessor().slickOptions || {};
// Initialize slick on the div, with provided options
$(element).slick(options);
//handle disposal, if KO removes the element
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).slick('unslick');
});
},
//update the control when the view model changes
update: function(element, valueAccessor) {
var images = ko.unwrap(valueAccessor());
// Do something to update the content
}
};
var vm = {
images: ko.observableArray(imageUrls),
options: {}
}
ko.applyBindings(vm, gallery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick.min.js"></script>
<link href="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/jquery.slick/1.5.8/slick-theme.css" rel="stylesheet">
<div id="gallery"
style="width:400px"
data-bind="slick: images, slickOptions: {dots:true, initialSlide:4}">
</div>
The missing part in the implementation is the updating of the gallery if the imgUrls changes. But it shows the main techniques in the hints.