【发布时间】:2014-01-03 23:24:33
【问题描述】:
我被一个较旧的 WebForms 项目困住了,我想知道是否有适合我的场景的推荐方法。
目标
- 我在使用 KnockoutJS 绑定的模式对话框中有一个反馈表。
- 我希望通过网站页脚中的链接在所有页面上提供反馈表。
- 我希望其他几个页面也使用淘汰赛以及他们自己的单独脚本和绑定,而不考虑模式中的反馈表单绑定。
- 我有一些页面根本不使用淘汰赛。我希望他们不必插入代码来完成此操作。
- 如果可能的话,我希望避免使用全局变量,而使用命名空间的 JavaScript。
- 本质上,我希望页面上的视图模型和反馈视图模型不知道彼此的存在。
当前设置
- 我们的页脚链接位于 Site.master 文件中,因此我放置了 Feedback.js 脚本和具有绑定的模式的 div。所以在母版页上,我打电话给
ko.applyBindings(vm, referenceToFeedbackDiv),它可以很好地连接反馈表。 - 我们的各个页面偶尔会有一个淘汰视图模型,因此他们可能会调用 ko.applyBindings(vm),因为据他们所知,他们希望将 vm 应用于整个页面。
问题
- 这会导致剔除冲突,因为通过 Site.master 调用将一个 vm 应用于反馈表单,而其后的页面将一个 vm 应用于整个正文。
问题
我怎样才能使这两个功能——一个跨所有使用剔除页面的模式对话框和单个剔除页面——协调工作?
(当前)代码中的问题演示
请记住,问题是我希望能够拥有一个仅适用于整个客户端站点的反馈 div 的反馈 VM,并且我希望能够应用其他不需要知道任何内容的 VM关于反馈 vm。
母版页文件 (Site.Master) -- 摘录
这是在每一页上:
<div class="page">
<div class="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
</div>
<div class="footer">
© <%=DateTime.Now.Year.ToString() %> Company, Inc. | <a href="/">Home</a> | <a
href="/about.aspx">About</a> |
<!-- begin feedback area -->
<span id="FeedbackArea">
<a data-bind="click: showModal">Feedback</a>
<div id="feedback-modal" title="What's on your mind?">
<div class="btn-group" id="feedbackButtonGroup">
<button class="btn" data-bind="click: UpdateFeedbackType" style="padding-top: 6px;">
<i class="fa fa-warning fa-2x fa-align-center"></i>
<br />
<span>Problem</span>
</button>
<button class="btn" data-bind="click: UpdateFeedbackType" style="padding-top: 6px;">
<i class="fa fa-question-circle fa-2x fa-align-center"></i>
<br />
<span>Question</span>
</button>
<button class="btn" data-bind="click: UpdateFeedbackType" style="padding-top: 6px;">
<i class="fa fa-lightbulb-o fa-2x fa-align-center"></i>
<br />
<span>Suggestion</span>
</button>
<button class="btn" data-bind="click: UpdateFeedbackType" style="padding-top: 6px;">
<i class="fa fa-thumbs-o-up fa-2x fa-align-center"></i>
<br />
<span>Praise</span>
</button>
<button class="btn" data-bind="click: UpdateFeedbackType" style="padding-top: 6px;">
<i class="fa fa-info-circle fa-2x fa-align-center"></i>
<br />
<span>General</span>
</button>
</div>
<br />
<br />
<textarea rows="5" placeholder="Enter feedback here" data-bind="value: feedbackText, valueUpdate: 'afterkeydown'"></textarea>
<br />
<br />
<button>Send Feedback</button>
<button data-bind="click: CancelFeedback">Cancel</button>
<h3>Other Information: </h3>
<ul>
<li><strong>Feedback Type:</strong> <span data-bind="text: feedbackType"></span></li>
<li><strong>Current URL:</strong> <span data-bind="text: pageUserIsOn"></span></li>
<li><strong>Current User: </strong><%=hdnLoggedInUsername.Value %></li>
<li><strong>Current Client: </strong>[Not yet captured]</li>
<li><strong>Current Tab: </strong>[Not yet captured]</li>
</ul>
</div>
</span>
<!-- End feedback area -->
</div>
Feedback.JS -- 这也包含在每个页面中
...FeedbackVM 的命名空间定义:
var FeedbackNamespace = FeedbackNamespace || {};
..命名空间本身的定义:
FeedbackNamespace = {
ViewModel: function () {
// etc. etc.
}
};
...以及 VM 变量的声明以及将其连接到 document.ready():
var FeedbackVM;
$(document).ready(function () {
FeedbackVM = new FeedbackNamespace.ViewModel();
ko.applyBindings(FeedbackVM, $('#FeedbackArea')[0]);
FeedbackVM.Start();
log('FeedbackVM started');
});
其他没有 Knockout / JS 的页面
其他页面上可能有也可能没有任何 javascript,更不用说淘汰赛了。在这些页面上,FeedbackVM 当前运行良好。
具有自己的 Knockout ViewModel 的页面
这些页面将拥有自己的命名空间 JS 文件和自己的 document.ready() 事件,该事件创建一个名为 invoiceUploaderVM = new InvoiceUploader.ViewModel() 的虚拟机,然后调用 ko.applyBindings(invoiceUploaderVM)。
这就是我们遇到麻烦的地方。
更新:一种可能的方法和一个小麻烦
在 Site.master 页面中,我将整个页脚包裹在 "stopBindings: true" div 中:
<div data-bind="stopBindings: true">
<div class="footer" id="footerDiv">
<!-- Feedback Viewmodel stuff in here -->
</div>
</div>
我已将stopBindings 定义为:
ko.bindingHandlers.stopBindings = {
init: function () {
return { controlsDescendantBindings: true };
}
};
我的 Feedback.js 文件作为全局 JS 文件的一部分加载到每个页面上,具有:
var FeedbackNamespace = FeedbackNamespace || {};
FeedbackNamespace = {
// defines viewmodel, etc. etc.
};
var FeedbackVM;
$(document).ready(function () {
FeedbackVM = new FeedbackNamespace.ViewModel();
ko.applyBindings(FeedbackVM, $('#footerDiv')[0]);
FeedbackVM.Start();
log('FeedbackVM started');
});
这种方法效果很好——只要没有绑定其他视图模型。在从我的母版页继承的页面上,我可能有类似的内容:
$(document).ready(function () {
'use strict';
vm = new invoiceUploader.ViewModel();
ko.applyBindings(vm);
});
我希望这样:
- 设置应用于 div 的反馈视图模型,停止其他视图模型
- 设置 invoiceUploader 视图模型并将其应用于正文(然后由 stopBindings div 停止)
但是,我在加载子页面时遇到错误:
注释行以应用反馈绑定使这项工作再次正常。
我做错了什么?
【问题讨论】:
-
您找不到“click: function() { return ToggleHelp }”的绑定的问题是由于范围界定问题。您需要更改绑定字符串,因此只需“单击:ToggleHelp”即可。或者从knockoutjs传入的回调数据中获取数据。见:knockoutjs.com/documentation/click-binding.html
标签: javascript asp.net knockout.js webforms master-pages