简体   繁体   中英

using prettyCheckable plugin with knockoutjs 2.1 checked data-binding doesn't work

I am using the prettyCheckable jquery plugin to make my checkboxes and radio buttons look pretty and if I use the data-bind="checked: dateMode" it doesn't work because the plugin hides the actual checkbox and makes it's own override html to pretty up the checkbox/radio, therefore the knockoutjs lib doesn't recognize when I check the radio or checkbox and update the value in the model. I know my code works fine if I don't use prettyCheckable plugin, so don't tell me my model or data binding code is messed up. I tested this.

https://github.com/arthurgouveia/prettyCheckable

Here is my partial view code.

<div id="DatesChooser" class="span5 pull-left">
    <h4><i class="icon-calendar"></i>Dates</h4>
    <input type="radio" name="Date" value="All" data-label="All Available" data-bind="checked: dateMode" /><br />
    <input type="radio" name="Date" value="Range" data-label="Range" data-bind="checked: dateMode" />
    <div data-bind="visible: dateMode() == 'Range'">
        <input type="text" id="FromYear" placeholder="1970" /> to
        <input type="text" id="ToYear" placeholder="2012" /><br />
        <div id="Date-Slider" class="ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all">
            <div id="Date-Slider-Bar" class="ui-slider-range ui-widget-header" style="left: 0%; width: 100%;"></div>
            <a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left: 0%;"></a>
            <a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left: 100%;"></a>
        </div>
    </div>
</div>

Here is my knockout model :

function searchVm() {
    var self = this;
    self.dateMode = ko.observable("All");
    self.startSearch = function () { alert(self.dateMode()); };
};

And I initialize the prettyCheckable stuff like this :

$('input:checkbox').prettyCheckable();
$('input:radio').prettyCheckable();

Here is what the code gets rendered as after the prettyCheckable plugin modifies it, notice how the input style is 'display:none' :

<div id="DatesChooser" class="span5 pull-left">
    <div class="clearfix prettyradio labelright blue">
        <input type="radio" data-bind="checked: dateMode" data-label="All Available" value="All" name="Date" style="display: none;" checked="checked">
        <a class="checked" href="#"></a>
        <label for="undefined">All Available</label>
    </div>
    <br>
    <div class="clearfix prettyradio labelright blue">
        <input type="radio" data-bind="checked: dateMode" data-label="Range" value="Range" name="Date" style="display: none;">
        <a class="" href="#"></a>
        <label for="undefined">Range</label>
    </div>
    <div data-bind="visible: dateMode() == 'Range'" style="display: none;">
        <input id="FromYear" class="placeholder" type="text" placeholder="1970">
to
        <input id="ToYear" class="placeholder" type="text" placeholder="2012">
        <br>
        <div id="Date-Slider" class="ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all">
            <div id="Date-Slider-Bar" class="ui-slider-range ui-widget-header" style="left: 0%; width: 100%;"></div>
            <a class="ui-slider-handle ui-state-default ui-corner-all" style="left: 0%;" href="#"></a>
            <a class="ui-slider-handle ui-state-default ui-corner-all" style="left: 100%;" href="#"></a>
            <div class="ui-slider-range ui-widget-header" style="left: 0%; width: 100%;"></div>
        </div>
    </div>
 </div>

Pretty Checkable triggers change events on the checkboxes, but Knockout looks for click events. This can be fixed with a change in prettyCheckable.js lines 46-54. Original:

    if (input.attr('checked') !== undefined) {
      input.removeAttr('checked').change();
    } else {
      input.attr('checked', 'checked').change();
    }

Changed:

    if (window.ko) {
      ko.utils.triggerEvent(input[0], 'click');
    } else {
      input.click();
    }

Knockout also won't work if you use jQuery's click trigger function. You must use Knockout's triggerEvent as above.

jsFiddle: http://jsfiddle.net/mbest/4cX48/

There is nothing wrong here. Pretty Checkable library works that way.

It finds the input dom hide them and put dynamic a and label tag instead of that input. If you want to find that input is checked or not you need to examine class of dynamically added a tag ( Class ="checked"). Not the orginal input tag.

You need to write a binding for prettycheckable and observe the a tag's class. Then change the checked value of your binding according to class of that a tag.

http://knockoutjs.com/documentation/custom-bindings.html

@Michael's modification to prettyCheckbox mostly worked, but if your viewModel already has a selection made when you load, prettyCheckbox will NOT recognize it because it is looking for the "checked" attribute while knockout/plain vanilla html will mark the checkbox as checked via a property .

in prettyCheckbox change:

var isChecked = el.attr('checked') !== undefined ? 'checked' : '';

to

var isChecked = el.prop('checked') == true ? 'checked' : '';

Also, it is important to know that if you modify your knockout viewmodel property in code, it will NOT be reflected in prettyCheckbox because I'm not aware of a way to subscribe (in javascript, not knockout) to a change in a property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM