【问题标题】:Data-binding MVC-4 to a Knockout.js foreach将 MVC-4 数据绑定到 Knockout.js foreach
【发布时间】:2012-10-27 00:23:20
【问题描述】:

我们的 Web 应用程序中有一个表单,它在一个地方要求用户输入一个值列表。我们使用 Razor 和 knockout.js 编写了表单的这一部分,以便列表的每个值都有一个文本框,类似于 this tutorial。我们如何将这些文本框数据绑定到我们的 MVC 模型?

这是我们的表格:

@model OurProject.Models.Input.InputModel
@{
    ViewBag.Title = "Input";
}
<h2>
    Inputs</h2>
<div id="inputKOApp">
    @using (Html.BeginForm())
    {
        <!-- snip - lots of part of our form that work correctly -->
        <div class="row-fluid">
            <div class="control-group">
                <div class="span8 control-label">
                    @Html.LabelFor(model => model.POSTransactionCodes)
                </div>
                <div class="controls">
                    <!-- These are the textboxes we would like to bind to MVC -->
                    <ul class="pull-right" data-bind="foreach: POSTransactionCodes">
                        <li>
                            <input data-bind="value: code" />
                            <a href="#" data-bind="click: $root.removePOSTransactionCode">Delete</a></li>
                    </ul>
                    <button class="pull-right" data-bind="click: addPOSTransactionCode">
                        Add another POS Transaction Code</button>
                    @Html.ValidationMessageFor(model => model.POSTransactionCodes, null, new { @class = "help-inline" })
                </div>
            </div>
        </div>
        <!-- snip - more cshtml that is irrelevant to the problem -->
</div>
        <input type="submit" value="Submit" />
    }
</div>
<script type="text/javascript" src='~/Scripts/jquery-1.8.2.min.js'></script>
<script type="text/javascript" src='~/Scripts/knockout-2.1.0.js'></script>
<script type="text/javascript" src='~/Scripts/OP/OP.js'></script>
<script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Form.js'></script>
<script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Data.js'></script>
<script type="text/javascript">
    var inputApp = $('#inputKOApp')[0];
    OP.Input.Form.init(inputApp);
</script>

这是我们的 knockout.js 脚本,OP.Input.Input.Form.js:

extend(OP, 'OP.Input.Form');
OP.Input.Form = function (jQuery) {
    var TransactionCodeView = function () {
        var self = this;
        self.code = "";
    };

    //The ViewModel for the page
    var ViewModel = function () {
        var self = this;        

        //Fields
        /* snip - lots of fields that work as expected */
        self.POSTransactionCodes = ko.observableArray([]); //is a list of transaction codes

        //Set up with initial data
        /* I'm guessing that we won't need this function anymore since MVC will populate
         * everything for us, but I'll leave it in until I'm far enough along to know
         * I won't need to gut lots of stuff */
        self.initialize = function () {
            var c = function (data, status, response) {
            /* snip - lots of fields that work as expected */
                if (status === "success") {
                    if(data.POSTransactionCodes != null) ko.utils.arrayPushAll(self.POSTransactionCodes, data.POSTransactionCodes);
                    self.POSTransactionCodes.valueHasMutated();
                } else {

                }
            };
            OP.Input.Data.GetInput(c);
        }

        //When saving, submit data to server
        self.save = function (model) {
            var c = function (data, status, response) {
                if (status === "success") {

                } else {
                }
            };
            OP.Input.Data.SaveInput(model, c);
        }

        //Modifying POSTransactionCodes array
        self.removePOSTransactionCode = function (POScode) {
            self.POSTransactionCodes.remove(POScode);
        }

        self.addPOSTransactionCode = function () {
            self.POSTransactionCodes.push(new TransactionCodeView());
        }
    };

    //Connect KO form to HTML
    return {
        init: function (elToBind) {
            var model = new ViewModel();
            ko.applyBindings(model, elToBind);
            model.initialize();
        }
    };
} ($);

这是我们的 MVC 模型:

namespace OurProject.Models.Input
{
    public class InputModel : IModel
    {
        //Snip - lots of properties that aren't interesting for this problem
        [Required]
        [DisplayName("POS Transaction Codes")]
        public List<double> POSTransactionCodes { get; set; }

        public InputModel()
        { }

        /* I ommitted a few other methods that
         * aren't relevant to this problem. */
    }
}

【问题讨论】:

    标签: razor knockout.js asp.net-mvc-4


    【解决方案1】:

    我不知道您如何将数据发送回服务器,但您需要以允许模型绑定的方式命名您的输入:

    如果您要绑定到列表/集合,您的输入应该是这样的名称:

    <input type="text" name="CollectionPropertyName[index]" />
    

    你可以阅读Model Binding To A List in this article

    所以您只需要为您的输入生成正确的名称:

    <input data-bind="value: code, attr: { name: 'POSTransactionCodes[' + $index() + ']' }" />
    

    您应该注意,上述解决方案可能仅适用于您使用提交按钮并发送数据form-urlencoded 如果您以 json 格式发送数据,您可能需要调整序列化逻辑以使模型绑定器满意:

    在这种情况下,您的 json 应该是这样的:

    {
       //...
       POSTransactionCodes: [ 1 , 3  ]
       //..
    }
    

    【讨论】:

      【解决方案2】:

      感谢 nemesv 的回答,让我明白这一点。

      但我需要有用于 jquery 验证的“正常”名称和 id 属性。所以我想出了编写自己的数据绑定器的想法。

      ko.bindingHandlers.nameId = {
          update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
              var value = valueAccessor(),
                  allBindings = allBindingsAccessor();
              var valueUnwrapped = ko.utils.unwrapObservable(value);
              var bindName = $(element).data('bind-name');
              bindName = bindName.replace('{0}', valueUnwrapped);
              $(element).attr({name : bindName, id : bindName});
          }
      };
      

      并在html中使用

      <input
            data-bind="value: qty, nameId: $index"
            data-bind-name="inventory[{0}].qty" />
      

      jsfiddle

      【讨论】:

        猜你喜欢
        • 2012-07-14
        • 2023-03-15
        • 1970-01-01
        • 1970-01-01
        • 2014-12-11
        • 1970-01-01
        • 2012-06-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多