Tomas Eklund
Tomas Eklund

Reputation: 633

Stying form elements with Uniform JS within Knockout templates

I am trying to learn Knockout while building a fairly complex dynamic form which is styled using the jQuery plugin Uniform JS. Since Knockout is dynamically building parts of the form on the fly I need to make sure Uniform JS keeps up and styles the dynamically generated form elements.

After some searching I found a blog post titled "Knockout JS knockouts" by Mikhail Temkine explaining how to write a custom Knockout binding to solve the problem with Uniform styled checkboxes. The custom binding looks like this:

ko.bindingHandlers.checkedUniform = {
    init: function (element, valueAccessor) {
        ko.bindingHandlers.checked.init(element, valueAccessor);
    },
    update: function (element, valueAccessor) {
        ko.bindingHandlers.checked.update(element, valueAccessor);
        $.uniform.update($(element));
    }
};

The simplified HTML looks something like this:

<ul data-bind="foreach: items">
    <li data-bind="text: name, click: $root.editItem, css: {bold: bolded()}"></li>
</ul>
<div data-bind="with: selectedItem">
    Edit list item: <input data-bind="value: name" />
    Make it bold: <input type="checkbox" data-bind="checkedUniform: bolded />
</div>

The custom binding apparently uses the uniform.update() method which is supposed to refresh the state of the styled checkboxes. Unfortunately it isn't working. The checkboxes are styled according to the selected Uniform design template, but as soon as the Knockout template is re-rendered (in this case when selectedItem changes) the indicator showing whether the checkbox is ticked or not is lost. The checkboxes are still functional, you can click them to toggle their state, it's just that they always show up as unchecked.

I have created a simple jsFiddle to demonstrate the problem:

http://jsfiddle.net/tomas_eklund/RaSpK/1/

Upvotes: 3

Views: 1670

Answers (1)

nemesv
nemesv

Reputation: 139788

Your styling get lost because when using the with binding it replaces the DOM underneath when its value changes. So your initial $('input[type="checkbox"]').uniform(); won't be applied to the newly created checkboxes.

To solve this instead of generally apply the uniform plugin move the initialization logic into your checkedUniform init function (it will run once a binding applied to an element even if the element was just created by KO):

ko.bindingHandlers.checkedUniform = {
    init: function (element, valueAccessor) {
        ko.bindingHandlers.checked.init(element, valueAccessor);
        $(element).uniform();
    },
    update: function (element, valueAccessor) {
        ko.bindingHandlers.checked.update(element, valueAccessor);
        $.uniform.update($(element));
    }
};

Demo JSFiddle.

Upvotes: 2

Related Questions