0

これが私が直面している問題であり、それにアプローチする方法さえわからない:

ASP.NET MVC 4でモデル、コントローラー、およびビューを作成しました。ある時点で動的リストを作成する必要があったため、この問題を非常に簡単に解決するKnockoutJSをオプトアウトしました。ここまでは順調ですね。次に、 Fluent Validationを使用してMVCモデルで定義した検証が、ノックアウトビューで機能しなくなったことに気付きました。

SOを検索したところ、実行可能な解決策はほとんど見つかりませんでした。

いくつかの理由で、私は後者を使用する傾向があります。主な理由は、別のライブラリを紹介(学習、テスト、ローカライズ、時間を費やす)しない機会を与えてくれるからです。

私はMVCに精通しており、メッセージやラベルなどを完全に制御できるローカリゼーションをサポートする方法が大好きです。また、Fluent Validationが大好きで、他のMVCに置き換えたくありません(静的で、ローカライズがはるかに難しく、柔軟性がはるかに低い)私の好み)

data-bindをdata_bindにする必要がある場合の、ノックアウトからかみそりへの変換の例をいくつか見つけました。

とでforeachループを表現する方法が見つかりません。

MVCビューモデル

  public class ContactEmail
  {
    public string SelectedLabel { get; set; }
    public string Name { get; set; }
  }

 public class User
 {
   public IList<ContactEmail> Emails { get; set; }
 }


ViewBag.EmailLabels = new string[] { "label1", "label2", ... };

ノックアウトモデル

  var viewModel = {
    EmailLabels: ko.observableArray(@Html.Json(ViewBag.EmailLabels as string[]) || []),
    Emails: ko.observableArray(@Html.Json(@Model.Emails) || []),
  } 

ノックアウトビュー(変換したかった)

    <table>
    <tbody data-bind="foreach: Emails">
      <tr>
        <td>
        @* How to make razor below work instead of knockout syntax below it? *@
        @*Html.DropDownListFor(m => ????, new { data_bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'" } )
          <select data-bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'"></select></td>
          <td>
            @* How to make razor below work as well instead of knockout syntax below ?!?!? *@
            @Html.TextBoxFor(m => ????, new { data_bind="value: Name, uniqueName: true" } )
              <input type="text" data-bind="value: Name, uniqueName: true" class="required email" />
          </td>
          <td>
              <a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a>
          </td>
      </tr>
    </tbody>
    </table>

私はMVCControlsツールキットを見て、 1人の男が容赦なく宣伝したものが、私のすべての検証とローカリゼーション、そしてすべてを解決します。私はそれが使用不可能で、非常に独占的で、理解するのが非常に難しいことに気づきました。鳥を殺すために核兵器を買うようなものです。

ですから、MVCとノックアウトを組み合わせた経験のある方はぜひステップアップして経験を共有してください。

どんな助けでも大歓迎です&事前にどうもありがとうございました。

4

2 に答える 2

0

編集:最終的なノックアウトバインディングを含めるように更新

index.cshtml

@model Stackoverflow5.Models.User

<form>
    <table>
        <tbody>

            @{
                var tempdropdownlist = new List<SelectListItem>();
            }
            @for (var i = 0; i < @Model.Emails.Count; i++)
            {
                <tr>
                    <td>
                        @Html.DropDownListFor(m => m.Emails[i], tempdropdownlist,
                            new { data_bind = String.Format("options: $root.EmailLabels, value: Emails()[{0}].SelectedLabel, optionsCaption: 'Choose...'", i)})
                    </td>
                    <td>
                        @Html.TextBoxFor(m => m.Emails[i].Name, 
                            new { data_bind = String.Format("value: Emails()[{0}].Name(), uniqueName: true", i) })
                    </td>
                </tr>
            }

        </tbody>
    </table>

    <button type="submit">Test</button>
</form>

**モデル(検証が機能している)**

public class ContactEmail
    {
        public string SelectedLabel { get; set; }

        [Required]
        [StringLength(20, MinimumLength = 2)]
        public string Name { get; set; }

    }

    public class User
    {
        public User()
        {
            Emails = new List<ContactEmail>();
            EmailLabels = new List<string> {"Important", "Spam", "Family"};
        }

        public List<ContactEmail> Emails { get; set; }
        public List<string> EmailLabels { get; set; }
    }
于 2013-03-10T14:01:41.887 に答える
0

これはちょっとしたハックだと思いますが、うまくいきます。

コントローラは、レンダリングする必要のあるリストを含むUser.Emailsプロパティ内の電子メールのコレクションを返します。Razor Viewが生成するのは、1行だけのテーブルのHTMLと、Emails IEnumerableの最初の要素に基づく検証です(これはnullをチェックする必要があります。そうしないと、例外が発生する可能性があります)。

クライアント側でko.applyBindings()が発生すると、tbodyタグのforeachによってすべての行が生成され、コレクション全体がマップされたJsonStringとして初期化されたko ViewModelなので、リスト全体がレンダリングされます。メソッドremoveEmailとaddEmailも同様に機能します(removeEmailオプションをテストしたところ、= Dで機能します)

@using Newtonsoft.Json
@model Stackoverflow5.Models.User

    <table>
        @{var tempdropdownlist = new List<SelectListItem>();}

        <tbody data-bind="foreach: Emails">
            <tr>
                <td>
                    @Html.DropDownListFor(m => m.Emails.First().SelectedLabel, tempdropdownlist,
                                      new { data_bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'" })

                <td>
                    @Html.TextBoxFor(m => m.Emails.First().Name, new { data_bind="value: Name, uniqueName: true" } )
                </td>
                <td>
                    <a href="#" data-bind="click: function () { viewModel.removeEmail(this); }">Delete</a>
                </td>
            </tr>
        </tbody>
    </table>


@section scripts
{
    <script src="~/Scripts/knockout-2.2.1.js"></script>
    <script src="~/Scripts/knockout.mapping-latest.js"></script>

    <script>
        //Model definition
        var viewModel,
            ModelDefinition = function (data) {
            //Object definition
            var self = this;

            //Mapping from ajax request
            ko.mapping.fromJS(data, {}, self);

            self.removeEmail = function(row) {
                self.Emails.remove(row);
            };

            self.addEmail = function() {
                //Method for adding new rows here
            };
        };

        $(function() {
            viewModel = new ModelDefinition(@Html.Raw(JsonConvert.SerializeObject(Model)));
            ko.applyBindings(viewModel);
        });
    </script>
}
于 2013-03-10T21:35:29.333 に答える