0

这是我面临的问题,甚至不知道如何解决它:

我在ASP.NET MVC 4中创建了模型、控制器和视图。有一次我不得不创建动态列表,所以我选择了KnockoutJS,这非常容易解决这个问题。到目前为止,一切都很好。然后我意识到我使用Fluent Validation在 MVC 模型上定义的验证在淘汰视图中不再起作用。

我搜索了 SO,发现几个可行的解决方案:

由于几个原因,我倾向于使用后一种。主要是因为它让我有机会介绍(学习、测试、本地化、花时间)另一个库。

我对 MVC 非常熟悉,并且喜欢它支持本地化的方式,可以完全控制消息、标签等。我也喜欢 Fluent Validation 并且不想用其他人替换它(更静态,更难本地化,更不灵活我的喜好)

当 data-bind 必须变为 data_bind 等时,我发现了一些关于敲除到剃刀转换的示例。

我找不到用和 in 来表达 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>

我查看了MVC Controls 工具包,一个人无情地宣传它将解决我所有的验证和本地化以及所有问题。我发现它无法使用,非常专有且极难理解。就像买核弹杀鸟一样。

因此,请那些有过将 MVC 与淘汰赛结合的经验的人,请站出来分享您的经验。

任何帮助将不胜感激,并在此先感谢您。

4

2 回答 2

0

我认为这有点骇人听闻,但它确实有效。

控制器将返回 User.Emails 属性内的电子邮件集合,其中包含需要呈现的列表。Razor 视图生成的是只有一行的表格的 HTML,并且验证基于 Emails IEnumerable 的第一个元素(必须检查是否为 null 或可能导致异常)。

当客户端发生 ko.applyBindings() 时,tbody 标记上的 foreach 将生成所有行,并且由于 ko ViewModel 已将整个集合初始化为映射的 JsonString,因此将呈现整个列表。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 回答
0

编辑:更新以包括明确的淘汰赛绑定

索引.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 回答