【问题标题】:How to use multiple checked data-binds on a single radio button using KnockoutJS?如何使用 KnockoutJS 在单个单选按钮上使用多个选中的数据绑定?
【发布时间】:2016-11-13 18:31:00
【问题描述】:

用户需要选择一个单选按钮。我的标签需要具有所选单选按钮的值,以便稍后在文本框中显示。我还需要将单选按钮的值存储在 Ajax“标题”变量中,以便我可以在后端(Python - Flask)上使用它。当我单击迁移按钮时,它会运行我的 Ajax 调用。

我读到我可以在数据绑定之间放置逗号,但是通过 data-bind="checked: $data.title, checked: radioFrom",它会将我的代码破坏到单选按钮不起作用的地方。但是,如果我只使用data-bind="checked: $data.title",那么我的 Ajax 调用就可以工作,但我的标签仍然是空白的(原因很明显)。

我如何获得它,以便我可以在我的单选按钮上使用两个选中的数据绑定,以便我的标签更新和我的 Ajax 调用工作?还是我缺少其他解决方案?

我的标题

<!DOCTYPE html>
<html>

    <script type='text/javascript' src='http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.4.0.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/json2/20150503/json2.js'></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

    <body>  
        {% extends "layout.html" %}
        {% block content %}
        <div id="tab">

我的单选按钮

<td id="myRadioFrom" class="label">From:</td>
<td>
    <label><input type="radio" value="DevQ" name="from" data-bind="checked: $data.title, checked: radioFrom" />DevQ</label>
    <label><input type="radio" value="Dev2" name="from" data-bind="checked: $data.title, checked: radioFrom" />Dev2</label>
</td>

我的标签

<tr>
    <td class="label">From:</td>
    <td data-bind="text: radioFrom"></td>
</tr>

我的按钮

<form>
    <span class="migrate"><button data-bind="click: $data.add" type="submit" class="btn btn-default" value="Migrate!" data-dismiss="modal">Migrate!</button></span>
</form>

我的 Javascript/KnockoutJS

<script>
    var TabViewModel = function(){
        var self = this;

        //Set href value of element
        self.selected = ko.observable(null);

        self.tasksURI = 'http://localhost:5000/todo/api/v1.0/tasks';    // Use to get root access to server
        self.username = "";
        self.password = "";
        self.tasks = ko.observableArray();

        self.radioFrom = ko.observable("");

        var btn = document.getElementById("myBtn");                 
        var span = document.getElementsByClassName("close")[0];

        controls.onchange = function() {
            console.log(viewModel.radioFrom());
        }

        self.ajax = function(uri, method, data)
        {
            var request = 
            {
                url: uri,
                type: method,
                contentType: "application/json",
                accepts: "application/json",
                cache: false,
                dataType: 'json',
                data: JSON.stringify(data),

                // beforeSend is invoked by jQuery, used to send a jqXHR object to get a request from $.aJax
                beforeSend: function (xhr)
                {
                    xhr.setRequestHeader("Authorization",
                        "Basic " + btoa(self.username + ":" + self.password));
                },
                // if $.aJax request comes back with an error such as invalid username
                error: function(jqXHR)
                {
                    console.log("ajax error " + jqXHR.status);
                }               
            };
            return $.ajax(request); // Returns value of the $.aJax request
        }

        self.add = function(task)
        {
            self.ajax(self.tasksURI, 'POST', task).done(function(data)
            {
                self.tasks.push
                ({
                    uri: ko.observable(data.task.uri),
                    title: ko.observable(data.task.title),
                    description: ko.observable(data.task.description),
                    done: ko.observable(data.task.done)
                });

            });
        }

    };
    window.viewModel = new TabViewModel();
    ko.applyBindings(window.viewModel, $('#tab')[0]);          
</script>

【问题讨论】:

    标签: javascript jquery python ajax knockout.js


    【解决方案1】:

    是的,您可以在单个控件上使用多个绑定,但您尝试做的是在单个控件上使用多个 SAME 绑定。如果将相同类型的绑定应用到控件敲除将选择相同绑定的第二次使用。你可能不想这样做。

    title 中保存的值已更新为包含当前选择的单选按钮的 value 属性的值,即输入中的 value="DevQ"value="Dev2"。这意味着存储在 $data.title 中的值正是您要查找的值!即您需要其值的单选按钮。看看下面的sn-p。希望它可以帮助您解决问题。

    ko.applyBindings({
      title: ko.observable('DevQ')
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <label>
      <input type="radio" value="DevQ" name="from" data-bind="checked: title" />DevQ</label>
    <label>
      <input type="radio" value="Dev2" name="from" data-bind="checked: title" />Dev2</label>
    <br/>
    <hr/>
    <br/>The value held in title() is updated to contain the value of the value attribute of the radio button that is selected
    <br/>
    <br/>
    <b id="myRadioFrom" class="label">From: </b><span data-bind="text: $data.title"></span>

    【讨论】:

    • 我当前的ko.applybindings 看起来像这样ko.applyBindings(window.viewModel, $('#tab')[0]);。我应该如何在我的场景中应用绑定?
    • 你可以简单地使用var tabViewModel = new TabViewModel();然后ko.applyBindings(tabViewModel, document.getElementById(tab));
    • 当我尝试上面提到的内容时出现此错误...knockout-min.js:63 Uncaught ReferenceError: Unable to process binding "checked: function (){return title }" Message: title is not defined。我应该如何解决这个问题?
    【解决方案2】:

    您不能在一个元素上使用相同的绑定两次,至少不能使用内置绑定。

    相反,您应该以每个函数都可以访问相关范围的方式构建视图模型。

    通常,我倾向于使用连接 Ajax 请求的根视图模型或父视图模型,并使用较小的视图模型用于域概念,例如 task。例如:

    // Fake jQuery ajax stuff:
    var $ = { ajax: function(options) { console.log(options); } };
    
    function Task() {
      this.title = ko.observable("");
    }
    
    function RootVm() {
      var self = this;
      
      self.user = ko.observable("fake-username");
      self.password = ko.observable("sec!ret");
      
      self.tasks = ko.observableArray([new Task(), new Task()]);
      
      function doAjaxCall(task) {
        $.ajax({
          data: task.title(),
          user: self.user(),
          password: self.password()
        });
      }
      
      self.migrate = function(task) {
        doAjaxCall(task);
      };
    }
    
    ko.applyBindings(new RootVm());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
    
    <ul data-bind="foreach: tasks">
      <li>
        Title:
        <input data-bind="textInput: title">
        <button data-bind="click: $root.migrate">migrate</button>
      </li>
    </ul>
    
    <hr>
    
    User: <input data-bind="textInput: user"><br>
    Password: <input data-bind="textInput: password">

    【讨论】:

    • 我有点迷路了。你能提供一些我的具体代码中的例子吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2021-08-13
    相关资源
    最近更新 更多