【问题标题】:POST a complex viewmodel to a controller将复杂的视图模型发布到控制器
【发布时间】:2012-12-18 03:31:36
【问题描述】:

我正在尝试掌握 Knockout (2.2.0) 背后的概念。
由于我正在使用 ASP.NET MVC 4,我想我可以遵循一个具有“复杂”视图模型(主详细信息)的示例。

我唯一能找到的是MvcMusicStore

代码很容易阅读,我已经弄清楚如何从服务器读取视图模型并在客户端构建视图模型。

这是我的 C# ViewModel

public class Person
{
    public Person()
    {
        this.Phones = new List<Phone>();
    }
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }

    public IList<Phone> Phones { get; set; }
}

public class Phone
{
    public string Model { get; set; }
    public string Number { get; set; }
}

我的控制器将填充模型返回给视图,视图将其转换为淘汰视图模型:

var data = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model));
var model = ko.mapping.fromJS(data);
ko.applyBindings(model);

我使用了与 Rob Conery 相同的模式,上面的代码是一个简化版本。

这是我的看法:

@using (@Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <input id="Name" name="Name" type="text" data-bind="value: Name" value="" />
    <br />
    <input id="Surname" name="Surname" type="text" data-bind="value: Surname" value="" />
    <br />
    <table>
    <tbody data-bind="foreach: Phones">
        <tr>
            <td><input type="text" data-bind='value: Model' /></td>
            <td><input type="text" data-bind='value: Number' /></td>
        </tr>
    </tbody>
    </table>
    <input type="submit" value="Send" />  
}

现在,我想提交我的 FORM 并在我的控制器上阅读更新后的视图模型。

为了实现这一点,我使用了在 MvcMusicStore 中找到的相同解决方案。
如果您查看line 49 Rob 尝试序列化 FORM:

var data = $("#orderForm").serialize();

并 POST 到控制器:

$.post("/orders/edit", data, callback);

我似乎无法使此代码与我的视图模型一起使用。 我的控制器:

[HttpPost]
public JsonResult Index(Models.Person viewModel)
{
...
}

似乎无法反序列化子级,如果调试客户端,我可以看到 seralize 方法也无法序列化它们。

实际上,我不明白他为什么要序列化 ​​FORM。因为我们有一个由淘汰赛管理的视图模型。 有没有其他方法可以序列化这样的“复杂”模型并将其发布到控制器?

您认为该解决方案 (MvcMusicStore) 做得正确还是我应该遵循其他模式?

任何帮助将不胜感激。

更新

我想我已经找到了解决方案,但我还需要进行更多测试。
如果我使用 toJSON KO 方法:

var data = ko.toJSON(model);

我可以正确序列化整个视图模型;然后我必须使用 $.ajax 发布数据

$.ajax({
    type: 'POST',
    dataType: 'json',
    contentType: 'application/json; charset=utf-8',
    url: "/Home/Index",
    data: dataToSave,
    success: callback,
    error: function (req, status, error) {
       alert("Status: " + status + " Error: " + error);
      }
});

这种方式似乎一切正常,但我仍然想知道是否有任何推荐的方法。

解决方案

Michael Berkompas 和 nemesv 给了我有用的信息,我整理了一个简单的application,以防其他人感兴趣。

【问题讨论】:

  • 感谢您的应用!这正是我所需要的!

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


【解决方案1】:

问题是在表格内你的input 元素没有name 属性。

你可以用attr binding来设置名字,因为MVC在model binding collection时需要一个特殊的名字格式,你需要写:

<tbody data-bind="foreach: Phones">
        <tr>
            <td><input type="text" data-bind="value: Model, attr: { name: 'Phones[' + $Index() + '].Model' }" /></td>
            <td><input type="text" data-bind="value: Number, attr: { name: 'Phones[' + $Index() + '].Number' }" /></td>
        </tr>
</tbody>

或者因为你有你的视图模型,你可以直接将它发送到你的控制器:

var model = ko.mapping.fromJS(data);

//...

$.ajax({
    type: 'POST',
    url: "/orders/edit",
    contentType: "application/json",
    data: ko.mapping.toJSON(model),
    success: callback
});

请注意,在这种情况下您不能使用$.post,因为您需要将contentType指定为“application/json”。

但我认为没有推荐的方法来做到这一点。 $("#orderForm").serialize()(使用我提到的正确输入名称)和ko.toJSON(model) 都有效,因为区别仅在于如何为 ajax 请求准备/编码数据。

我认为这更像是个人偏好使用哪个。在这种特殊情况下,使用ko.toJSON(model) 方式似乎更好,因为您不必处理为 ASP.NET MVC 生成特殊输入名称的问题。您可以将视图模型原样发送到服务器。而且用knockout感觉更自然。

【讨论】:

  • 其实可以使用$.post$.post(url, data, fn, "json");
  • @MichaelBerkompas 没有第四个参数是dataType:预期的数据类型from the server。但是对于 ASP.NET MVC,您需要设置 contentType 这是数据的类型 sent to sensver.
  • 嗯...我从来没有对我们的 MVC 应用程序的任何 $.post 调用这样做。但是,如果您希望返回的响应类型为 JSON,则您确实需要指定响应类型。
  • 感谢您的回复 nemesv。我已经更新了我的问题原因,与此同时,我找到了与您类似的解决方案。
  • @nemesv 你真的很聪明。感谢您抽出宝贵时间提供此答案。我在这个(复杂类型列表)上遇到了困难,因为我使用的是 $.post 方法而不是 $.ajax 以及 ko.toJS 而不是 ko.mapping.toJSON。非常感谢!
【解决方案2】:

我会选择 nemesv 的第二个选项。发布序列化的视图模型,而不是尝试使用 jQuery 序列化表单。

由于您的数据类型很复杂,并且 Asp.net MVC 无法将其转换为视图模型,您还需要使用 this page 中解释的 $.toDictionary() 插件。

var model = ko.mapping.fromJS(data);

//...

$.post("/orders/edit", $.toDictionary(ko.toJS(model)), callback, "json");

【讨论】:

  • 感谢您的回复迈克尔。我已经更新了我的问题,因为我认为我找到了解决方案。我似乎无法使用 toJS 并且我已经阅读了您链接的文章,但它似乎已经过时了。我希望能找到更好的解决方案,也许还能找到一些文章或示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
相关资源
最近更新 更多