【问题标题】:Binding and checking radiobuttons in Knockout JS在 Knockout JS 中绑定和检查单选按钮
【发布时间】:2014-03-03 14:31:25
【问题描述】:

在淘汰 JS 方面遇到更多问题,希望有人能够帮助我。 (我不得不问关于 Knockout 的大量问题,我想知道我是否应该坚持使用 jQuery)

我正在尝试使用两个或三个选项动态创建单选按钮列表。每行是一组单独的按钮。

我可以写出清单,但我很难找到合适的清单来检查或不检查。

我的 HTML 是:

<div data-bind="with: functions" id="ActionWindow">
<h2>bob<span data-bind="text: pgroupname"></span></h2>

<h2>Read & Update Functions</h2>

<div>
<table>
    <thead class="FunctionsTableHead">
        <tr>
            <th class="FunctionName">Function</th>
            <th>None</th>
            <th>Read</th>
            <th>Write</th>
        </tr>
    </thead>

    <tbody class="FunctionsTable" data-bind="foreach: pReadFunctions">
        <tr>
            <td class="FunctionName" data-bind="text: FunctionName"></td>
            <td><label><input type="radio" data-bind="attr: { name: FunctionNum + '-ReadAccessLevel'}, checkedValue: 0, checked: AccessLevel" /></label></td>
            <td><label><input type="radio" data-bind="attr: { name: FunctionNum + '-ReadAccessLevel'}, checkedValue: 1, checked: AccessLevel" /></label></td>
            <td><label><input type="radio" data-bind="attr: { name: FunctionNum + '-ReadAccessLevel'}, checkedValue: 2, checked: AccessLevel" /></label></td>
        </tr>
    </tbody>

</table>
</div>

<h2>Action Functions</h2>

    <table>
    <thead class="FunctionsTableHead">
        <tr>
            <th class="FunctionName">Function</th>
            <th>None</th>
            <th>Action</th>
        </tr>
    </thead>

    <tbody class="FunctionsTable" data-bind="foreach: pActionFunctions">
        <tr>
            <td class="FunctionName" data-bind="text: FunctionName"></td>
            <td><label><input type="radio" data-bind="attr: { name: FunctionNum + '-ActionAccessLevel'}, checkedValue: 0, checked: AccessLevel" /></label></td>
            <td><label><input type="radio" data-bind="attr: { name: FunctionNum + '-ActionAccessLevel'}, checkedValue: 1, checked: AccessLevel" /></label></td>
        </tr>
    </tbody>

</table>

我为这两个单选按钮列表尝试了两种不同的方法,但都没有奏效:

<script type="text/javascript">

//slide animation for lefthand menu 
$('.ListDeptLink').click(function () {
    $(this).nextAll('.SectListDiv').first().slideToggle(500);
});

$('.ListSectLink').click(function () {

    var url = '@Url.Action("DisplayGroup", "AjaxGroup")' + '?GroupId=' + $(this).attr("GroupId") + "&GroupName=" + encodeURIComponent($(this).attr("GroupName"));

    $.ajax({
        url: url,
        contentType: "application/json; charset=utf-8",
        type: 'POST',
        context: this,
        timeout: 60000,
        dataType: 'json',
        tryCount: 0,
        retryLimit: 3,
        success: function (data) {
            viewModel.functions(new functionsModel(data))
        },
        error: function (httpRequest, textStatus, errorThrown) {
            alert("Error");
        }
    });
});

function functionsModel(data) {
    this.pgroupname = ko.observable(data ? data.GroupName : "");
    this.FunctionNum = data ? data.FunctionNum : "";
    this.AccessLevel = data ? data.AccessLevel : "";

    this.pReadFunctions = ko.observableArray((data ? data.ReadFunctionList : [])
        .map(function (item) {
            return {
                FunctionNum: item.FunctionNum,
                FunctionName: item.FunctionName,
                AccessLevel: ko.observable(item.AccessLevel)
            };
        })
    );

    this.pActionFunctions = ko.observableArray((data ? data.ActionFunctionList : [])
        .map(function (item) {
            return {
                FunctionNum: item.FunctionNum,
                FunctionName: item.FunctionName,
                AccessLevel: ko.observable(item.AccessLevel)
            };
        })
    );
};

var wrapper = function () {
    this.functions = ko.observable(new functionsModel(null));
};

var viewModel = new wrapper();

ko.applyBindings(viewModel);

最后是返回数据的示例:

ReadFunctionList":[],"ActionFunctionList":     [{"FunctionNum":582,"FunctionName":"Name1","FunctionType":Ignorethis,"GroupNum":1,"AccessLevel":0},{"FunctionNum":502,"FunctionName":"Name2","FunctionType":IgnoreThis,"GroupNum":2,"AccessLevel":0},"GroupName":"Name1"}

AccessLevel 决定了应该勾选哪个,所以在这个例子中,两个项目都应该勾选第一个单选按钮。

提前感谢您的帮助:)

编辑:我已经更新了到目前为止的代码

【问题讨论】:

  • 一个显示问题的工作 jsfiddle 会很棒
  • 我正在努力,但我什至无法让 JS Fiddle 填充行:jsfiddle.net/dariune/sYTF7
  • 您的第一个问题是您没有遵循淘汰赛应遵循的任何设计模式。您正在混合敲除和 jQuery,并使用 jQuery 来做应该用敲除处理的事情。我强烈建议您遵循淘汰教程并像那里一样构建您的代码。
  • 看看你的包装函数。您创建一个 observableArray 然后用非数组值填充,删除第二行。与成功回调相同。那确实应该将一个新值推入 observableArray -> viewModel.functions.push(new functionsModel(data)) ;
  • 在让 jsFiddle 工作方面,将 click 事件中的 AJAX 调用替换为对 viewModel.functions 的直接分配......此外,JQuery 将点击处理程序连接到的元素在哪里.您还缺少从包装器到函数的绑定(“foreach:functions”?)

标签: jquery asp.net-mvc knockout.js


【解决方案1】:

Javascript 问题

我认为 wrapper 中的函数应该是 observable,而不是 observableArray。

var wrapper = function () {
    this.functions= ko.observable(new functionsModel(null));
};

您的 pReadFunction 和 pActionFunction 项目应具有 AccessLevel 属性作为可观察对象。您不会通过将单选按钮更改为视图模型来获得更新。

// Inside $('.ListSectLink').click
this.pReadFunctions = ko.observableArray( (data ? data.ReadFunctionList : [] )
    .map( function(item) {
        return {
            FunctionNum: item.FunctionNum,
            FunctionName: item.FunctionName,
            FunctionType: item.FunctionType,
            GroupNum: item.GroupNum,
            AccessLevel: ko.observable(item.AccessLevel)
        }; 
    })
);

// Repeat for pActionFunctions

在您的 jsFiddle 中,不要在点击处理程序中使用 AJAX 调用,只需直接分配您的示例数据。如果你真的想模拟一个异步回调,使用 $.Deferred / resolveWith。

$('.ListSectLink').click(function () {
    var testData = ...
    viewModel.functions( new functionsModel(testData) );
});

$('.ListSectLink').click(function () {
    var testData = ...
    var deferred = $.Deferred();
    deferred.done( function(data) {
        this.functions( new functionsModel(data) );
    });

    setTimeout( function() {
        deferred.resolveWith(viewModel, [testData]);
    }, 100);

});

HTML/绑定问题

在您的 jsFiddle 中,缺少 wrapper->functions 绑定。这可能是样本不起作用的原因。假设类似。

<div data-bind="with: functions" />

Input Radios 检查绑定不应该针对 $root。在您的示例中,这将是 wrapper 实例。鉴于您的示例 JSON,AccessLevel 位于每个 ReadFunctionList 和 ActionFunctionList 数组项上,因此使用 "$data.AccessLevel" (或只是 "AccessLevel" )检查数据绑定

检查的绑定与元素的值和支持的 observable 进行比较。但是元素的绑定是一个 string,但在您的示例 JSON 中它是一个 number。这将不匹配。添加一个checkedValue数据绑定表达式,将每个单选按钮的“值”覆盖为数字。

您还需要为 pReadFunction 单选按钮使用名称 attr 绑定,就像对 pActionFunction 单选按钮所做的那样,将每一行分组为一组。您也可以考虑为 Read 和 Action 添加另一个前缀,以防 FunctionNum 在 2 个集合之间不是唯一的。

<input type="radio" data-bind="
    attr: { name: 'Action-' + FunctionNum + '-AccessLevel'}, 
    checkedValue: 0,
    checked: AccessLevel" />

<input type="radio" data-bind="
    attr: { name: 'Action-' + FunctionNum + '-AccessLevel'}, 
    checkedValue: 1,
    checked: AccessLevel" />

奖励积分

您也可以使用点击绑定来代替 jQuery。 click 函数将是包装类上的一个函数。您需要传入 Url,因为它看起来像是在服务器端生成的。我正在使用一个按钮来连接示例的数据绑定。您可能需要帮助 razor 引擎在 data-bind 属性中计算出客户端和服务器端。我将把它作为练习留给读者;)

这里的好处是所有模型操作都包含在 viewModel 中。还要注意点击数据绑定表达式上的 bind 语句。这是您将参数输入函数的方式。如果“包装器”不是根对象,您可能需要根据实际的 applyBindings/viewModel 结构将其更改为 $data 或 $parent。在 jsFiddle 中它会起作用。

<button data-bind="click: getListSectLink.bind($root, @Url.Action(...)">Get</button>

function wrapper() {
    this.functions = ko.observable( new FunctionsModel(null ) );
    this.getListSectLink = function(url) {
         // ajax stuff
         success: function(data) {
             this.functions( new functionsModel(data) );
         }
    };
}

【讨论】:

  • 您好,感谢您的广泛回复。我已经编辑了我的 JSFiddle 和我的代码,但仍然无法正常工作。在我的代码中,它会写出数据列表,但没有勾选任何内容。在 JSFiddle 上,我什至无法让它写出数据。你介意看看吗? jsfiddle.net/sYTF7/2
  • 我已经更新了jsFiddle。您的版本没有引用 jQuery,我已将淘汰版本更新为 3.0.0,因为 check/checkedValue 绑定已得到增强。如果您必须使用 2.3.0,那么您仍然需要在每个输入单选上使用 value 属性,并且 AccessLevel observable 将变成一个字符串。
【解决方案2】:

问题在于 Knockout 使用精确比较来确定选择哪个单选按钮,并且您绑定到整数 checked 值,同时为单选按钮提供字符串 attr 值。解决方案是使用checkedValue 绑定(而不是attr)给单选按钮一个整数值:

<input type="radio" data-bind="checkedValue: FunctionNum, checked: $root.AccessLevel" />

参考:http://knockoutjs.com/documentation/checked-binding.html#parameters

【讨论】:

  • 这是3.0.0的特性,勾选的绑定不正确
猜你喜欢
  • 2012-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
相关资源
最近更新 更多