淘汰嵌套列表 Post 空

Knockout Nested List Post Null

我正在尝试将 ko 集成到我的一个剃刀视图中。我昨天研究了很多,但没能为我的问题找到类似的解决方案。

我有一个唱片型号:

public class Record
{
    public Int Request Id {get;set;}
    public string RecordName {get;set;}
    public Person Person {get;set;}
    public IList<Person> People { get; set; }        
}

还有一个人物模型:

public class Person
{        
    public int Id { get; set; }    
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public IList<Alias> Aliases { get; set; }
}

我的看法:

@model Record
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm("PostRequest", "Request", FormMethod.Post))
{
@Html.LabelFor(m => m.Person.FirstName)
@Html.TextBoxFor(m => m.Person.FirstName)

<h5>People</h5>
<table>
    <tbody data-bind="foreach: People">
        <tr>
            <td>@Html.LabelFor(m => m.Person.FirstName)</td>
            <td><input type="text" data-bind="value: FirstName, attr: {name:     'People[' + $index() + '].FirstName'}" /></td>
            <td>@Html.LabelFor(m => m.Person.LastName)</td>
            <td><input type="text" data-bind="value: LastName, attr: {name: 'People[' + $index() + '].LastName'}" /></td>
        </tr>

        <tr>                
            <td><button id="removePerson" data-bind="click: $root.removePerson">Remove Person</button></td>
        </tr>
        <tr>
            <td>
                <button id="addAlias" data-bind="click: addAlias">Add Alias</button>
            </td>
        </tr>
        <!-- ko foreach: Aliases -->
        <tr>
            <td>@Html.LabelFor(m => m.Alias.FirstNameAlias)</td>
            <td><input type="text" data-bind="value: FirstNameAlias, attr: {name: 'Aliases[' + $index() + '].FirstNameAlias'}" /></td>
            <td>@Html.LabelFor(m => m.Alias.LastNameAlias)</td>
            <td><input type="text" data-bind="value: LastNameAlias, attr: {name: 'Aliases[' + $index() + '].LastNameAlias'}" /></td>
            <td><button id="removeAlias" data-bind="click: $root.removeAlias">Remove Alias</button></td>
        </tr>
        <!-- /ko -->
    </tbody>
</table>

<button id="addPerson" data-bind="click: addPerson">Add Person</button>
<button>Submit</button>
<input id="clickMe" type="button" value="clickme" onclick="submit();" />

}

和脚本:

@section scripts
{

<script type="text/javascript">
    $(function () {

        var personItem = function () {
            var self = this;

            self.LastName = ko.observable();
            self.FirstName = ko.observable();
            self.Aliases = ko.observableArray();

        };

        var model = ko.mapping.fromJS(@Html.Raw(Model.ToJson()));

        alert('The length of the array is ' + model.People().length);
        alert('The first element is ' + model.People()[0].Aliases().length);
        alert(ko.toJSON(model));
        model.addPerson = function () {
            model.People.push(new personItem());
        };

        model.removePerson = function (person) {
            model.People.remove(person);
        };

        ko.applyBindings(model);
    })

    function submit() {
        $.ajax({
            url: '/Request/PostRequest',
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            data: ko.toJSON(model),

            success: function (status) {
                alert(status);

            }
        });
    };
</script>
}

获取此视图的控制器操作会预先初始化记录模型的一些数据,因此绑定似乎正常工作,但是当我 post 数据时,别名列表的数据返回 Null。

控制器:

    public ActionResult CreateRequest(Record viewModel)
    {
        var list = new Record
        {

            People = new List<Person> {

                    new Person {FirstName = "My First Person", Aliases = new List<Alias> { new Alias{FirstNameAlias = "firstnamealias",LastNameAlias = "lastnamealias1"}},},
                    new Person {FirstName = "My Second Person", Aliases = new List<Alias> { new Alias{FirstNameAlias = "firstnamealias2", LastNameAlias ="lastnamealias2"}},}

                },
            Person = new Person()
            {
                FirstName = "me"
            }

        };


        return View(list);
    }
    [HttpPost]
    public JsonResult PostRequest(Record viewModel)
    {


        return Json(String.Format("'Success':'false','Error':'"));
    }

我觉得我在 ko.mapping 中缺少了一些东西。但是如此接近,因为数据是从 GET 控制器操作填充的,但未能 POST。

解决方案

我更新了我的击倒脚本,以及我在视图中呈现击倒数据的方式。这解决了我的问题。

更新脚本

<script>


var initialData = @Html.Raw(Serialize(Model.People));

var BackgroundModel = function(people) {
    var self = this;
    self.people = ko.mapping.fromJS(people);


    self.addPerson = function() {
        self.people.push({
            FirstName: "",
            LastName: "",
            Aliases: ko.observableArray()
        });
    };

    self.removePerson = function(person) {
        self.people.remove(person);
    };

    self.addAlias = function(person) {
        person.Aliases.push({
            //todo
            FirstNameAlias: "",
            LastNameAlias: ""
        });
    };

    self.removeAlias = function(Alias) {
        $.each(self.people(), function() { this.Aliases.remove(Alias) })
    };

    self.save = function() {
        self.lastSavedJson(JSON.stringify(ko.toJS(self.people), null, 2));
        var subModel = JSON.stringify(ko.toJS(self));
        $.ajax({
            url: '/Request/PostRequest',
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            data: subModel,

            success: function (status) {
                alert(status);

            }
        });
    };

    self.lastSavedJson = ko.observable("")
};

ko.applyBindings(new BackgroundModel(initialData));

</script>

更新视图

            <div data-bind="foreach: people">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h4 class="panel-title"> <a data-bind="attr:{href:'#collapseOne'+$index()}, text:FirstName() +' '+ LastName()" @*href="#collapse_One"*@ class="accordion-toggle" data-toggle="collapse" data-parent="#accordion"></a> </h4>
                    </div>
                    <div data-bind="attr:{id:'collapseOne'+$index()}" class="panel-collapse collapse in" @*data-bind="attr:{id:_collapseId, class:_collapsedIn}"*@>
                        <div class="panel-body">
                            <table>
                                <tbody>
                                    <tr>
                                        <td>@Html.DisplayNameFor(x => x.Person.FirstName)</td>
                                        <td>@Html.DisplayNameFor(x => x.Person.LastName)</td>                                          
                                    </tr>
                                    <tr>
                                        <td><input data-bind="value: FirstName, name: FirstName" /></td>
                                        <td><input data-bind="value: LastName, name: LastName" /></td>
                                    </tr>

                                    <tr>                                        
                                        <td><a href='#' data-bind='click: $root.removePerson'>Remove Person</a></td>
                                    </tr>
                                </tbody>
                            </table>
                            <!-- ko foreach: Aliases -->


                            <table>
                                <tbody>
                                    <tr>
                                        <td>@Html.DisplayNameFor(x => x.Alias.FirstNameAlias)</td>
                                        <td>@Html.DisplayNameFor(x => x.Alias.LastNameAlias)</td>
                                    </tr>
                                    <tr>
                                        <td><input data-bind="value: FirstNameAlias, name: FirstNameAlias" /></td>
                                        <td><input data-bind="value: LastNameAlias, name: LastNameAlias" /></td>
                                    </tr>
                                    <tr>
                                        <td><a href='#' data-bind='click: $root.removeAlias'>Remove Alias</a></td>
                                    </tr>
                                </tbody>
                            </table>

                            <!-- /ko -->

                            <a href='#' data-bind='click: $root.addAlias'>Add Alias</a>
                        </div>
                    </div>
                </div>
            </div>

您提交函数中的变量 model 将是 undefined 这不是您期望的模型。

将提交方法移至您的模型中...

$(function () {

    var personItem = function () {
        var self = this;

        self.LastName = ko.observable();
        self.FirstName = ko.observable();
        self.Aliases = ko.observableArray();

    };

    var model = ko.mapping.fromJS(@Html.Raw(Model.ToJson()));

    alert('The length of the array is ' + model.People().length);
    alert('The first element is ' + model.People()[0].Aliases().length);
    alert(ko.toJSON(model));
    model.addPerson = function () {
        model.People().push(new personItem());
    };

    model.removePerson = function (person) {
        model.People().remove(person);
    };

    model.submit = function() {
        $.ajax({
            url: '/Request/PostRequest',
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            data: ko.toJSON(model),

            success: function (status) {
                alert(status);
            }
        });
    };

    ko.applyBindings(model);
});

并将按钮上的绑定更新为

<input id="clickMe" type="button" value="clickme" data-bind="click: submit" />

还有

Controller.Json 期望序列化对象而不是字符串

[HttpPost]
public JsonResult PostRequest(Record viewModel)
{
    return Json(String.Format("'Success':'false','Error':'"));
}

应该是:

[HttpPost]
public JsonResult PostRequest(Record viewModel)
{
    return Json(new { success = false, error: String.Empty });
}

更新

还注意到更新 model.People 数组的另一个问题

model.addPerson = function () {
    model.People.push(new personItem());
};

model.removePerson = function (person) {
    model.People.remove(person);
};

在这些函数中 model.People 应该是 model.People(),即

model.addPerson = function () {
    model.People().push(new personItem());
};

model.removePerson = function (person) {
    model.People().remove(person);
};

注意 model.People 之后的 () - 包含在上面的代码块中。