无法检查通过Knockout动态添加的jQuery-Mobile复选框

时间:2013-09-22 14:36:08

标签: jquery-mobile knockout.js checkbox

我尝试使用Knockout向我的页面添加复选框。 但是,通过单击它们无法检查那些动态添加的复选框。 如果我使用jQuery添加一个框,则生成的HTML与Knockout复选框不同。 input包含在另一个<div class="ui-checkbox">中。 如果未使用自定义绑定checkbox,也没有区别。 有人知道如何解决这个问题吗?

  • jQuery:1.10.2
  • jQuery-Mobile:1.3.2
  • 淘汰赛:2.3.0

这是一个小提琴:http://jsfiddle.net/USpX5/

HTML:

<div id="fiddle" data-bind="foreach: boxes">
    <label>
        <input type="checkbox" />
        <span data-bind="text: name"></span>
    </label>
</div>

JS:

var BoxModel = function(id, name) {
    this.id = ko.observable(id);
    this.name = ko.observable(name);
};

var MainModel = function()
{
    this.boxes = ko.observableArray([]);
}
var main = new MainModel();

$('#add-ko').click(function() {
    var i = $('#fiddle').find('input[type=checkbox]').length + 1;
    main.boxes.push(new BoxModel('id'+i, 'name'+i));
});
$('#add-jqm').click(function() {
    var i = $('#fiddle').find('input[type=checkbox]').length + 1;
    $('#fiddle').append('<label><input type="checkbox" /><span>name'+i+'</span></label>').trigger('create');
});

// http://stackoverflow.com/a/15841271/2710739
ko.bindingHandlers.checkbox = {
    init: function(element, valueAccessor) {    
        // set the dom element to a checkbox and initialize it (for jquerymobile)
        var checkbox = $(element);
        checkbox.checkboxradio();
        checkbox.attr('type', 'checkbox');
    },
    update: function(element, valueAccessor) {
        // update the checked binding, i.e., check or uncheck the checkbox
        ko.bindingHandlers.checked.update(element, valueAccessor);

        // and refresh the element (for jquerymobile)
        var checkbox = $(element);
        checkbox.checkboxradio('refresh');
    }
};

ko.applyBindings(main);

生成的HTML(从Chrome DevTools复制):

<div id="fiddle" data-bind="foreach: boxes">

    <!-- added with ko -->
    <div class="ui-checkbox">
        <label data-corners="true" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="checkbox-off" data-theme="c" data-mini="false" class="ui-checkbox-off ui-btn ui-btn-corner-all ui-fullsize ui-btn-icon-left ui-btn-up-c">
            <span class="ui-btn-inner">
                <span class="ui-btn-text">
                    <span data-bind="text: name">name1</span>
                </span>
                <span class="ui-icon ui-icon-checkbox-off ui-icon-shadow">&nbsp;</span>
            </span>
        </label>
        <div class="ui-checkbox"><!-- additional ui-checkbox class maybe causes the problem -->
            <input type="checkbox" data-bind="checkbox:true">
        </div>
    </div>

    <!-- added with jqm -->
    <div class="ui-checkbox">
        <label data-corners="true" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="checkbox-off" data-theme="c" data-mini="false" class="ui-checkbox-off ui-btn ui-btn-corner-all ui-fullsize ui-btn-icon-left ui-btn-up-c">
            <span class="ui-btn-inner">
                <span class="ui-btn-text">
                    <span>name2</span>
                </span>
                <span class="ui-icon ui-icon-checkbox-off ui-icon-shadow">&nbsp;</span>
            </span>
        </label>
        <input type="checkbox">
    </div>
</div>

2 个答案:

答案 0 :(得分:2)

以下是Knockout v3的更新小提琴:http://jsfiddle.net/USpX5/12/

主要的调整是绑定的更新方法。

update: function(element, valueAccessor) {       
    if (ko.bindingHandlers.checked.update) {
         ko.bindingHandlers.checked.update(element, valueAccessor);
    }
    else 
    {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).prop( "checked", value);
    }

    // and refresh the element (for jquerymobile)
    var checkbox = $(element);
    checkbox.checkboxradio('refresh');
}

答案 1 :(得分:1)

我再次调查jQuery Mobile Demos并找到data-role="none"。它可以防止JQM自动增强元素。现在我可以添加复选框,然后让BindingHandler通过checkbox.checkboxradio()增强它们。

现在复选框如下所示:

<button data-bind="click: add">Add checkbox</button>

<!-- show checked boxes -->
Checked: 
<div id="checkedBoxes" data-bind="foreach: boxes">
    <span data-bind="text: name, if: checked"></span>
</div>
<hr>

<!-- checkboxes -->
<div id="newBoxes" data-bind="foreach: boxes">
    <label>
        <input type="checkbox" data-bind="checkbox: checked" data-role="none" />
        <span data-bind="text: name"></span>
    </label>
</div>

在BindingHandlers init方法中,checkbox.removeAttr('data-role')用于让JQM通过checkbox.checkboxradio()增强元素:

ko.bindingHandlers.checkbox = {
    init: function(element, valueAccessor) {    
        // set the dom element to a checkbox and initialize it (for jquerymobile)
        var checkbox = $(element);
        // let jquerymobile enhance the element
        checkbox.removeAttr('data-role');
        // make it so
        checkbox.checkboxradio();
        // register change event to update the model on changes to the dom
        checkbox.on('change', function(e) {
            valueAccessor()(this.checked);
        });
    },
    update: function(element, valueAccessor) {
        // update the checked binding, i.e., check or uncheck the checkbox
        ko.bindingHandlers.checked.update(element, valueAccessor);

        // and refresh the element (for jquerymobile)
        var checkbox = $(element);
        checkbox.checkboxradio('refresh');
    }
};

var BoxModel = function(id, name, checked) {
    var self = this;
    self.id = ko.observable(id);
    self.name = ko.observable(name);

    // checkbox state
    self.checked = ko.observable(checked);    
};

function MainViewModel()
{
    var self = this;
    // hold all added checkboxes
    self.boxes = ko.observableArray([]);

    // add new checkbox
    self.add = function () {
        var i = $('#newBoxes').find('input[type=checkbox]').length + 1;
        self.boxes.push(new BoxModel('id'+i, 'name'+i, false));
    }
}

ko.applyBindings(new MainViewModel());

这是一个更新的小提琴:http://jsfiddle.net/USpX5/5/