Knockout with MVC3: Knockout Model не будет публиковать данные сбора? - PullRequest
3 голосов
/ 23 марта 2012

ОТВЕТ: Замена этой строки:

self.identifiers.push(new Identifier(self.identifierToAdd(), self.selectedIdentifierTypeValue()));

На эту строку:

self.identifiers.push({ Key: self.identifierToAdd(), Value: self.selectedIdentifierTypeValue()});

Запросы на отправку теперь отправляют данные сбора правильно.Однако это не решает тот факт, что действие MVC не получает его, но этот вопрос уже достаточно велик.


Я не могу получить данные из свойства коллекции моей модели в нокаутев мою модель MVC при публикации действий.Если я предупреждаю ko.toJSON мое identifiers() свойство снизу, оно правильно отображает все данные, но когда я пытаюсь отправить эти данные с помощью обычной обратной передачи (действие просто принимает EquipmentCreateModel ниже), оно выглядит следующим образом:

state of model upon submit

Идентификаторы пусты, и когда я смотрю на ошибку ModelState для идентификаторов, она говорит, что это cannot convert String to Dictionary<Guid, string>.Что я делаю неправильно?Я думал, что MVC3 автоматически преобразует JSON в объекты, если это возможно, как это было сделано со свойствами BuildingCode и Room?

Кроме того, почему мои строковые данные на приведенном выше рисунке экранированы кавычками?


РЕДАКТИРОВАТЬ: Если я смотрю данные поста, идентификаторы отображаются в виде пустого массива (identifiers: [{}]).Я попытался jsoning идентификаторы в методе сохранения, например, так:

self.identifiers = ko.toJSON(self.identifiers());

Это приводит к тому, что данные запроса не пустые и выглядят так:

identifiers:"[{\"Value\":\"sdfsd\",\"Key\":\"4554f477-5a58-4e81-a6b9-7fc24d081def\"}]"

Однако такая же проблема возникает, когдаЯ отлаживаю действие.Я также пытался jsoning всю модель (как описано в knockoutjs submit с проблемой ko.utils.postJson ):

ko.utils.postJson($("form")[0], ko.toJSON(self));

Но это дает ошибку .NET, которая говорит Operation is not valid due to the current state of the object., чтоесли посмотреть на данные запроса, то это выглядит так, будто они дважды JSON-ified, потому что каждая буква или символ - это свое собственное значение в коллекции HttpCollection, и это потому, что .NET по умолчанию разрешает только 1000 макс.текущее состояние ошибки объекта во время обратной передачи ).

При использовании метода $ .ajax для отправки данных все работает нормально:

 $.ajax({
            url: location.href, 
            type: "POST",
            data: ko.toJSON(viewModel),
            datatype: "json",
            contentType: "application/json charset=utf-8",
            success: function (data) { alert("success"); }, 
            error: function (data) { alert("error"); }
        });

Но по другим причинамЯ не могу использовать метод $ .ajax для этого, поэтому мне нужно, чтобы он работал в обычном посте.Почему я могу toJSON весь viewModel в запросе ajax, и он работает, но при обычной обратной передаче он разделяет его, а когда нет, все кавычки экранируются в отправленном JSON.


Вот моя ViewModel:

public class EquipmentCreateModel
{
//used to populate form drop downs
public ICollection<Building> Buildings { get; set; }
public ICollection<IdentifierType> IdentifierTypes { get; set; }

[Required]
[Display(Name = "Building")]
public string BuildingCode { get; set; }

[Required]
public string Room { get; set; }

[Required]
[Range(1, 100, ErrorMessage = "You must add at least one identifier.")]
public int IdentifiersCount { get; set; } //used as a hidden field to validate the list
public string IdentifierValue { get; set; } //used only for knockout viewmodel binding

public IDictionary<Guid, string> Identifiers { get; set; }
}

Тогда мой сценарий выбивания / ViewModel:

<script type="text/javascript">
// Class to represent an identifier
function Identifier(value, identifierType) {
    var self = this;
    self.Value = ko.observable(value);
    self.Key = ko.observable(identifierType);
}

// Overall viewmodel for this screen, along with initial state
function AutoclaveCreateViewModel() {
    var self = this;

    //MVC properties
    self.BuildingCode = ko.observable();
    self.room = ko.observable("55");
    self.identifiers = ko.observableArray();
    self.identiferTypes = @Html.Raw(Json.Encode(Model.IdentifierTypes));
    self.identifiersCount = ko.observable();


    //ko-only properties
    self.selectedIdentifierTypeValue = ko.observable();
    self.identifierToAdd = ko.observable("");

    //functionality
    self.addIdentifier = function() {
        if ((self.identifierToAdd() != "") && (self.identifiers.indexOf(self.identifierToAdd()) < 0)) // Prevent blanks and duplicates
        {
            self.identifiers.push(new Identifier(self.identifierToAdd(), self.selectedIdentifierTypeValue()));
            alert(ko.toJSON(self.identifiers()));
        }
        self.identifierToAdd(""); // Clear the text box
    };

    self.removeIdentifier = function (identifier) {
        self.identifiers.remove(identifier);
        alert(JSON.stringify(self.identifiers()));
    };

    self.save = function(form) {
        self.identifiersCount = self.identifiers().length;
        ko.utils.postJson($("form")[0], self);
    };
}
    var viewModel = new EquipmentCreateViewModel();
    ko.applyBindings(viewModel);
    $.validator.unobtrusive.parse("#equipmentCreation");      
    $("#equipmentCreation").data("validator").settings.submitHandler = viewModel.save;

View:

@using (Html.BeginForm("Create", "Equipment", FormMethod.Post, new { id="equipmentCreation"}))
{
@Html.ValidationSummary(true)
<fieldset>
    <legend>Location</legend>
    <div class="editor-label">
        @Html.LabelFor(model => model.BuildingCode)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.BuildingCode, new SelectList(Model.Buildings, "BuildingCode", "BuildingName", "1091"), "-- Select a Building --", new { data_bind = "value:BuildingCode"})
        @Html.ValidationMessageFor(model => model.BuildingCode)
    </div>
    <div class="editor-label">
        @Html.LabelFor(model => model.Room)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(model => model.Room, new { @class = "inline width-7", data_bind="value:room"})
        @Html.ValidationMessageFor(model => model.Room)
    </div>
</fieldset>
<fieldset>
    <legend>Identifiers</legend>
    <p>Designate any unique properties for identifying this autoclave.</p>
    <div class="editor-field">
        Add Identifier
        @Html.DropDownList("identifiers-drop-down", new SelectList(Model.IdentifierTypes, "Id", "Name"), new { data_bind = "value:selectedIdentifierTypeValue"})
        @Html.TextBox("identifier-value", null, new { @class = "inline width-15", data_bind = "value:identifierToAdd, valueUpdate: 'afterkeydown'" })
        <button type="submit" class="add-button" data-bind="enable: identifierToAdd().length > 0, click: addIdentifier">Add</button>
    </div>

    <div class="editor-field">
        <table>
            <thead>
                <tr>
                    <th>Identifier Type</th>
                    <th>Value</th>
                    <th></th>
                </tr>
            </thead>
            <!-- ko if: identifiers().length > 0 -->
            <tbody data-bind="foreach: identifiers">

                <tr>
                    <td>
                        <select data-bind="options: $root.identiferTypes, 
                        optionsText: 'Name', optionsValue: 'Id', value: Key">
                        </select>
                    </td>
                    <td><input type="text" data-bind="value: Value"/></td>
                    <td><a href="#" class="ui-icon ui-icon-closethick" data-bind="click: $root.removeIdentifier">Remove</a></td>
                </tr>


            </tbody>
            <!-- /ko -->
            <!-- ko if: identifiers().length < 1 -->
            <tbody>
                <tr>    
                    <td colspan="3"> No identifiers added.</td>
                </tr>
            </tbody>
            <!-- /ko -->
        </table>
        @Html.HiddenFor(x => x.IdentifiersCount, new { data_bind = "value:identifiers().length" })<span data-bind="text:identifiers"></span>
        @Html.ValidationMessageFor(x => x.IdentifiersCount)
    </div>    
</fieldset>
<p>
    <input type="submit" value="Create" />
</p>
}

1 Ответ

1 голос
/ 23 марта 2012

Я думаю, что нашел проблему или, по крайней мере, сузил ее. Пример редактируемой сетки использует простые объекты js для представления подарков. Вы используете объекты идентификаторов с суб-наблюдаемыми. Кажется, что если мы обновим пример сетки, чтобы использовать более сложные типы, он тоже сломается так же, как ваш пример. Это либо дизайн, либо ошибка.

http://jsfiddle.net/SZzVW/9/

Я думаю, что единственное решение - написать собственную функцию отображения для отправки формы.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...