如何更新mvc3应用程序中的淘汰模型

时间:2012-10-25 22:10:36

标签: asp.net-mvc-3 knockout.js

我和KnockoutJs一起玩MVC3几个星期了,我一直想知道什么

说我有一个mvc动作,它返回一个简单的列表

public ActionResult AddFoos()
{
    List<Foo> funds = new List<Foo>();     
    .. etc
    return Json(funds.ToList(), JsonRequestBehavior.AllowGet);
}     

然后传递到视图模型

var viewModel = {
  fooChocies: ko.mapping.fromJS([]),
  fooOptions: ko.mapping.fromJS([]),
    loadInitialData: function () {

        ko.mapping.fromJS(serverData, dataMappingOptions, viewModel.fooOptions);
    },
};

在我的Foo类型中,我也有显示或隐藏ui元素的属性

var Foo = function (data, preselect) {


    var self = this;
    self.id = ko.observable(data.id);
    self.Name = ko.observable(data.Name);
    self.number = ko.observable('');


    self.showProducts = ko.observable(false);   <---
    self.displayBigPanel = ko.observable(false);  <---

   }

我的方法是动态创建表单元素

通过ModelBinder并创建一个List&lt; Foo&gt;作为控制器动作的参数。

最后问题 ...

当用户导航回此页面时,我需要使用用户制作的fooChoices恢复用户界面。

似乎我有两个选择来重建用户选择(都通过扩展方法)

  1. 使用原始json,如

    所示
    ko.toJSON(viewModel.fooChoices))  
    
  2. 除基本模型属性外,还提供有关隐藏和显示UI元素的信息,

                sb.Append("viewModel.fooCghoices= ko.mapping.fromJS(" + json + ");");
                sb.Append("ko.applyBindings(viewModel);");
                return new HtmlString(sb.ToString());
    

    因此将客户端ui信息发送到服务器并返回

    1. 直接操作ViewModel,模拟用户操作

              sb.Append("viewModel.fooChoices.push(new Foo(1509));");
              sb.Append("viewModel.fooChoices()[0].selectedSubFoo = new Foo(273);");
              sb.Append("viewModel.fooChoices()[0].showProducts(true);");
      
    2. 在任何一种情况下,它感觉有点偏离,并且那里有更好的模式。想知道一种方式是否比上述方式更好或者没有方法。

      非常感谢

1 个答案:

答案 0 :(得分:1)

目前,您的控制器方法返回Foo列表。考虑创建一个更复杂的对象,同时保存你的Foos和你的选择。

public class FooViewModel 
{
  public List<Foo> Foos { get; set; };
  public UserChoices { get; set; }
}

更改控制器方法,使其返回FooViewModel。这意味着用户选择将与您感兴趣的任何Foos一起返回。

public ActionResult AddFoos()
{
    // Are there any choices stored in session?
    // Use those first, otherwise create a new UserChoices object
    UserChoices choices = 
        Session["User.Choices"] as UserChoices ?? new UserChoices();


    List<Foo> funds = new List<Foo>();     
    .. etc

    FooViewModel vm = new FooViewModel() { Foos = funds; UserChoices = choices };

    // Return the whole object, containing Choices and Foos
    return Json(vm, JsonRequestBehavior.AllowGet);
}

另外,请考虑某种动作过滤器,以便您轻松传递完整的对象。 ObjectFilter是一个很好的方法。它允许您轻松传递复杂的对象结构,而无需依赖特定的标记。

http://www.c-sharpcorner.com/blogs/863/passing-json-into-an-asp-net-mvc-controller.aspx

控制器方法上方的ObjectFilter。非常简单,只是声明控制器应该尝试将名为fooStuff的任何传入参数视为类型FooViewModel

    [HttpPost, 
     ObjectFilter(Param = "fooStuff", RootType = typeof(FooViewModel)), 
     UnitOfWork]
    public JsonResult ProcessFoos(FooViewModel fooStuff) {

通过定义相应的JavaScript视图模型,您可以将整个事物转换为json字符串并将其传递给完全填充的控制器方法。

因此,相应的js vm的例子是: -

var fooViewModel = function(data) {
  var self = this;
  self.Foos = ko.observableArray(data.Foos);
  self.UserChoices = ko.observable(data.UserChoices);


  // Don't worry about properties or methods that don't exist
  // on the C# end of things.  They'll just be ignored.
  self.usefulJSOnlyMethod = function() {
    // behaviour
  };
}

var userChoice = function(data) {
  var self = this;
  self.DinnerId = ko.observable(data.DinnerId);
}

对由ObjectFilter修饰的控制器方法的典型调用将是这样的(假设self是fooViewModel): -

var queryData = ko.mapping.toJSON(self);
$.ajax(
   //...
   data: queryData,

来自js vm的任何匹配(同名,相同类型区分大小写)属性将自动以控制器方法的fooStuff参数结束。是时候保存这些选择: -

另请注意,我在会话中坚持用户选择。这将允许他们被任何其他可能需要它们的控制器方法拾取(例如上面的AddFoos)。

    [HttpPost, 
     ObjectFilter(Param = "fooStuff", RootType = typeof(FooViewModel)), 
     UnitOfWork]
    public JsonResult ProcessFoos(FooViewModel fooStuff) 
    {
        // hey!  I have a fully mapped FooViewModel right here!
        // ( _fooServices.ProcessFoos will return updated version of viewmodel )
        FooViewModel vm = _fooServices.ProcessFoos(fooStuff);

        // What about those choices?
        // Put them in the session at this point in case anyone else comes asking
        // after them.
        Session["User.Choices"] = vm.UserChoices;

        return Json(vm);
    }

因为我们: -

  • 定义了更好的C#视图模型
  • 定义了相应的JS视图模型
  • 将UserChoices包含在该视图模型中

....此时恢复选择很简单。引用包含用户所选选项的视图模型部分。

<select id="dinnerChoice"
   data-bind="value: UserChoices.DinnerId"
>
</select>