3

Webアプリケーションには、値のリストを入力するようにユーザーに求めるフォームが1か所にあります。このチュートリアルのように、リストの値ごとにテキストボックスが表示されるように、Razorとknockout.jsを使用してフォームのこの部分を作成しました。これらのテキストボックスを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. */
    }
}
4

2 に答える 2

2

データをサーバーに送り返す方法がわかりませんが、モデルのバインドを可能にする方法で入力に名前を付ける必要があります。

リスト/コレクションにバインドする場合、入力は次のような名前にする必要があります。

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

この記事でリストへのモデルバインディングについて読むことができます

したがって、入力に適切な名前を生成する必要があります。

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

上記のソリューションは、送信ボタンを使用している場合にのみ機能しform-urlencoded、データをjsonとして送信している場合はデータを送信する場合にのみ機能することに注意してください。モデルバインダーを満足させるには、シリアル化ロジックを微調整する必要があります。

この場合、jsonは次のようになります。

{
   //...
   POSTransactionCodes: [ 1 , 3  ]
   //..
}
于 2012-11-07T06:11:26.370 に答える
1

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

于 2014-04-10T03:23:36.997 に答える