Knockout Nested List Post Нуль

Я пытаюсь интегрировать ко на одном из моих взглядов бритвы. Вчера я немного исследовал, но не смог найти аналогичного решения для моей проблемы.

У меня есть модель записи:

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

Действие Controller, которое ПОЛУЧАЕТ это представление, предварительно инициализирует некоторые данные для модели записи, поэтому привязка, кажется, работает должным образом, однако, когда я публикую данные, данные для Alias ​​List возвращаются к нулю.

контроллер:

    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.

РЕШЕНИЕ

Я обновил свой KO-скрипт и то, как я рендерил KO-данные в виде. Это решило мою проблему.

Обновленный скрипт

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

1 ответ

Решение

Переменная 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);
};

Обратите внимание на () после модели. Люди - включены в блок кода выше.

Другие вопросы по тегам