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 を復元する必要があります。

ユーザー選択の再構築には2つの選択肢があるようです(両方とも拡張メソッドを使用)

  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。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。非常に単純で、コントローラーがfooStufftypeと呼ばれるすべての着信パラメーターを処理しようとすることを宣言するだけFooViewModelです。

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

対応するJavaScriptビューモデルを定義することで、すべてをjson文字列に変換し、完全に入力されたコントローラーメソッドに渡すことができます。

したがって、対応するjsvmの例は次のようになります。

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>
于 2012-10-26T11:06:46.140 に答える