在Layout和Content页面中绑定ViewModel时,无法多次应用绑定

时间:2013-12-18 02:18:38

标签: asp.net-mvc knockout.js

我正在尝试将我的MVC应用程序的_Layout页面转换为使用knockout viewmodel而不是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>

如果内容页面没有内部viewmodel声明,则此方法有效。但是当我加载索引页面(带有第一个片段)时,我得到以下内容:

  

未捕获错误:您无法多次将绑定应用于同一元素。

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

3 个答案:

答案 0 :(得分:2)

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

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

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

现在,如果您遇到嵌套元素,则可以自己控制降序绑定。您可以指定一个语句,该语句将停止父元素与子元素的绑定。请在http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html上了解详情。

答案 1 :(得分:1)

你可以通过在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>

答案 2 :(得分:0)

ko.applyBindings可以有两个参数,第一个是您的viewmodel,第二个是要设置的绑定上下文的可选根节点。如果未提供任何值,则根节点默认为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/