【问题标题】:Cannot apply bindings multiple times - when binding a ViewModel in Layout and Content page无法多次应用绑定 - 在布局和内容页面中绑定 ViewModel 时
【发布时间】:2014-01-06 01:34:14
【问题描述】:

我正在尝试将我的 MVC 应用程序的 _Layout 页面转换为使用淘汰视图模型而不是 Razor 语法。到目前为止,我所有的内容页面都有如下语法来呈现 javascript ViewModels(用于索引视图):

<script type="text/javascript">
$(document).ready(ko.applyBindings(new IndexVm(
    @Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() })))));
</script>

到目前为止,这一直很好。现在,在我的布局中,我尝试使用以下相同的方法:

<script type="text/javascript">
$(document).ready(ko.applyBindings(new LayoutVm(
    @Html.Raw(JsonConvert.SerializeObject(ViewBag, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() })))));
</script>

如果内容页面没有内部视图模型声明,则此方法有效。但是当我加载索引页面(使用第一个 sn-p)时,我得到以下信息:

未捕获的错误:您不能将绑定多次应用于同一个元素。

对于为什么这不起作用,我有点难过。任何帮助将不胜感激!

【问题讨论】:

  • 一种解决方法可能是在 _Layout 页面的视图模型中声明您的内部视图模型的 observables 和 observableArrays。然后在您的内容页面上,只需用数据填充这些可观察对象。当然,这取决于您的项目范围、您使用的数据的详细信息等

标签: asp.net-mvc knockout.js


【解决方案1】:

ko.applyBindings 可以接受两个参数,第一个是您的视图模型,第二个是用于设置绑定上下文的可选根节点。如果未提供任何值,则根节点默认值为window.document.body。如果您调用 applyBindings 两次而不指定不同的根节点,那么它会给您您收到的错误。

请记住,您不想重叠正在绑定的节点。如果您需要为两个单独的视图模型调用两次 applyBindings,则必须指定要绑定到的不同元素:

ko.applyBindings(new MenuVM(), document.getElementById('menu'));
ko.applyBindings(new ContentVM(), document.getElementById('sub-content'));

编辑 根据 rwisch45 的评论,一个选项是将单个视图模型绑定到整个页面,并在主视图模型中设置子视图模型。

http://jsfiddle.net/TNR89/

【讨论】:

    【解决方案2】:

    您必须了解,在将 HTML 文档发送到浏览器之前,ASP.NET 将在服务器上完成某些任务。它将解释 Razor 语句并将部分视图、视图和布局组合到服务器上的单个 HTML 文档中。

    Knockout 是在客户端(浏览器)上运行的框架。如果您在 _Layout.cshtmlIndex.cshtml 中应用绑定,则会在组合的 HTML 文档中应用两次绑定。在 Knockout 中,您不能对同一个 HTML 元素多次应用绑定。

    您需要做的是为某些 HTML 元素添加一个具有有意义值的 id 属性。然后,您需要向不同的 ko.applyBindings 添加第二个参数,该参数将作为元素 ID。

    现在,如果您遇到嵌套元素的情况,您始终可以自己控制降序绑定。您可以指定一个语句来阻止父元素的绑定沿子元素向下移动。在http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html 上了解更多信息。

    【讨论】:

      【解决方案3】:

      你可以通过简单地在 html 中提供占位符来做到这一点:

      <div id="index">
         <!-- index page goes here -->
      </div>
      

      <div id="layout">
         <!-- layout page goes here -->
      </div>
      

      然后您可以按如下方式应用视图模型:

      <script type="text/javascript">
      $(document).ready(ko.applyBindings(new IndexVm(
      @Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }))), document.getElementById('index')));
      </script>
      

      <script type="text/javascript">
      $(document).ready(ko.applyBindings(new LayoutVm(
      @Html.Raw(JsonConvert.SerializeObject(ViewBag, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }))), document.getElementById('layout')));
      </script>
      

      【讨论】:

        猜你喜欢
        • 2016-09-19
        • 2019-12-16
        • 2021-01-13
        • 2019-01-18
        • 2015-11-14
        • 1970-01-01
        • 2018-09-16
        • 2019-11-09
        • 1970-01-01
        相关资源
        最近更新 更多