I've created a <dl>
where the <dd>
can be slideDown
/slideUp
by a click on the corresponding <dt>
by using knockout's databinding. I derived my solution from the tutorial about creating custom bindings.
So far I managed to wire everything so that I can click on a <dt>
and toggle the <dd>
. The plan was to keep the <dd>
s initially hidden but somehow I am not able achieve this.
Here's a simplified sample demonstrating the problem:
HTML
:
<dl data-bind="foreach: items">
<dt data-bind="click: toggleDefinition">DT: Lorem ipsum</dt>
<dd data-bind="slideVisible: definitionVisible, slideDuration: 300">DD: dolor sit amet</dd>
</dl>
JavaScript
:
ko.bindingHandlers.slideVisible = {
init: function (element, valueAccessor) {
var value = ko.unwrap(valueAccessor());
$(element).toggle(value);
},
update: function (element, valueAccessor, allBindings) {
var value = ko.unwrap(valueAccessor());
var duration = allBindings.get('slideDuration') || 400;
if (value) {
$(element).slideUp(duration);
} else {
$(element).slideDown(duration);
}
}
};
var model = function(){
var self = this;
self.items = ko.observableArray([
new item(),
new item(),
new item()
]);
};
var item = function(){
var self = this;
self.definitionVisible = ko.observable(false);
self.toggleDefinition = function (e)
{
self.definitionVisible(!self.definitionVisible());
};
};
ko.applyBindings(new model());
What I've tried:
to hide the <dd>
s by CSS
but it doesn't work like I had hoped (I didn't notice any difference):
dd {
display: none;
}
to set the following property to true
- it partialy works - it hides the <dd>
s but you can see the animation hiding them which is not desirable:
self.definitionVisible = ko.observable(true);
I also build a working demo at jsfiddle
Do you know what else I could try or change to keep the <dd>
s hidden until I click on a <dt>
?
I don't understand why the update
function gets called that shows the items again. I was trying to find what triggers it but the call stack does not help much (everything comes from knockout which cannot be traced).
The update function is triggered correctly as described in the documentation:
Knockout will call the update callback initially when the binding is applied to an element and track any dependencies (observables/computeds) that you access
Beside that your handler is not working because you missed some cases in your logic: you try to show/hide based on the current value but you should check the following instead:
definitionVisible
is true
-> then show the elementdefinitionVisible
is false
-> then hide the elementTranslating it to your code:
update: function (element, valueAccessor, allBindings) {
var value = ko.unwrap(valueAccessor());
var duration = allBindings.get('slideDuration') || 400;
if ($(element).css('display') != 'none' && !value) {
$(element).slideUp(duration);
}
if ($(element).css('display') == 'none' && value) {
$(element).slideDown(duration);
}
}
Demo JSFiddle.