0

我已经用 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< Foo > 作为控制器操作的参数。

最后的问题...

当用户导航回此页面时,我需要使用用户创建的 fooChoices 恢复 UI。

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

  1. 使用原始 json,如

    ko.toJSON(viewModel.fooChoices))  
    

除了基本的模型属性之外,它还提供了关于隐藏和显示 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);");
    

无论哪种情况,它都感觉有点不对劲,而且有更好的模式。想知道一种方法是否比另一种更好,或者以上都没有。

非常感谢

4

1 回答 1

1

目前,您的控制器方法返回一个Foo. 考虑创建一个更复杂的对象,该对象同时包含您的 Foo 和您的选择。

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

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

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视为 type 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 是 a 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>
于 2012-10-26T11:06:46.140 回答