Knockout Nested List Post Null

时间:2015-04-24 12:44:57

标签: asp.net-mvc razor knockout.js knockout-mapping-plugin

我正在尝试在我的一个剃刀视图上集成ko。我昨天研究了很多但是找不到针对我的问题的类似解决方案。

我有一个记录模型:

Foldable

一个人模型:

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();" />

获取此视图的Controller操作会初始化记录模型的某些数据,因此绑定似乎正常工作,但是当我发布数据时,Alias List的数据将返回Null。

控制器:

@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>
}

我觉得我错过了ko.mapping的东西。但是如此接近,因为数据从GET控制器操作填充,但无法POST。

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

更新了脚本

    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':'"));
    }

更新了视图

<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>

1 个答案:

答案 0 :(得分:2)

提交功能中的变量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);
};

注意模型之后的()。人 - 包含在上面的代码块中。