我是asp.net mvc4和knockoutjs的新手,需要帮助了解视图的工作原理。
我在共享文件夹中有一个_Layout.vbhtml,它是项目中所有页面的“主”页面。
我有AccountController,HomeController和GrowerController
我在Views文件夹中有GrowerController的Grower文件夹。索引是通常的默认视图。
在Views / Grower / Index中,我有一个从服务器检索数据的knoockout ViewModel。
现在,当我转到Home / Index等其他视图时,我在Firebug的控制台中看到,即使我不在我创建的视图中,它也会从服务器获取数据淘汰赛ViewModel。
我很困惑。是否会发生因为我对所有页面使用_layout.vbhtml?我做错了什么?
修改 *的 _Layout.vbhtml *
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewData("Title")</title>
<meta name="viewport" content="width=device-width" />
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.css" rel="stylesheet" type="text/css" />
@* Javascrips files *@
<script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="@Url.Content("http://code.jquery.com/jquery-1.7.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/custom.js")" type="text/javascript"></script>
<!-- Custom stylesheet overriding styles -->
@If Request.QueryString("pr") = "dow" or ViewData("pr") = "dow" Then
@<link rel="stylesheet" href="@Url.Content("~/Content/CustomDow.css")" />
Else
@<link rel="stylesheet" href="@Url.Content("~/Content/Custom.css")" />
End If
</head>
<body>
<div data-role="page" data-theme="b">
<div data-role="header">
@If IsSectionDefined("Header") Then
@RenderSection("Header")
Else
@<h1>@ViewData("Title")</h1>
@Html.Partial("_LoginPartial")
End If
</div>
<div data-role="content">
@RenderBody()
</div>
</div>
@RenderSection("scripts", required:=False)
</body>
的种植者/ Index.vbhtml 的
@Code
ViewData("Title") = "Select a Grower/Branch"
End Code
@section scripts
<script type="text/javascript">
function SuperViewModel() {
//====== GrowerInfo =======
var self = this;
self.GrowerName = ko.observable();
self.GrowerCompany = ko.observable();
self.GrowerAddress = ko.observable();
self.ShowGrowerCompany = ko.observable();
self.GrowerID = ko.observable();
self.updateGrowerInfo = function () {
$.getJSON("GetGrower", function (allData) {
self.GrowerName(allData.Name);
self.GrowerCompany(allData.CompanyName);
self.GrowerAddress(allData.Address);
self.ShowGrowerCompany(allData.ShowCompany);
self.GrowerID(allData.ID);
});
};
//Load initial state from server and populate viewmodel
self.updateGrowerInfo();
//========= End GrowerInfo ==========
if ($("#hfFlag").val() == "1") {
//========= BranchInfo ==========
self.BranchName = ko.observable();
self.Company = ko.observable();
self.Address = ko.observable();
self.ID = ko.observable();
//Load initial state from server and populate viewmodel
self.updateBranchInfo = function () {
$.getJSON("GetBranch", function (allData) {
self.BranchName(allData.Name);
self.Company(allData.CompanyName);
self.Address(allData.Address);
self.ID(allData.ID);
});
};
self.updateBranchInfo();
//=========== End BranchInfo ==============
}
//=============== GrowerList ===============
var MyGrower = function (data) {
this.growerId = ko.observable(data.GrowerId);
this.growerName = ko.observable(data.GrowerName);
};
self.growers = ko.observableArray([]);
self.updateGrowers = function () {
//refresh listview
$("#ulGrowerList").listview();
$("#ulGrowerList").listview("refresh");
$.getJSON("GetGrowers", function (allData) {
var mappedGrowers = $.map(allData, function (item) { return new MyGrower(item) });
self.growers(mappedGrowers);
});
};
self.setSelectedClassToGrowerList = function (item, event) {
$(ulGrowerList).closest('ul').find('a').removeClass('highlight');
$(ulGrowerList).closest('ul').find('.selected').remove();
$(event.target).toggleClass("highlight");
if ($(event.target).hasClass("highlight")) {
$(event.target).append("<span class='selected'>Selected</span>");
replaceByValue('GrowerID', event.target.id);
postjsonToServerNow("grower");
//update GrowerInfo
$.getJSON("GetGrower", function (allData) {
self.GrowerName(allData.Name);
self.GrowerCompany(allData.CompanyName);
self.GrowerAddress(allData.Address);
self.ShowGrowerCompany(allData.ShowCompany);
self.GrowerID(allData.ID);
});
} else {
$(event.target).find(".selected").remove();
}
};
self.setSelectedClassToBranchList = function (item, event) {
$(ulBranchList).closest('ul').find('a').removeClass('highlight');
$(ulBranchList).closest('ul').find('.selected').remove();
$(event.target).toggleClass("highlight");
if ($(event.target).hasClass("highlight")) {
$(event.target).append("<span class='selected'>Selected</span>");
replaceByValue('BranchID', event.target.id);
postjsonToServerNow("branch");
} else {
$(event.target).find(".selected").remove();
}
};
//Load initial state from server and populate viewmodel
self.updateGrowers();
//============ End GrowerList =============
}
//============= End ViewModel Section ====================//
$(document).bind('pageinit', function () {
//enable ko
ko.applyBindings(new SuperViewModel());
$("#divBranchList").hide();
//show hide lists
$("#btnGrower").click(function () {
$("#divGrowerList").show();
$("#divBranchList").hide();
});
$("#btnBranch").click(function () {
$("#divBranchList").show();
$("#divGrowerList").hide();
});
});
</script>
End Section
<table class="maintable" id="maintable">
<tr>
<td class="left">
<div id="GrowerInfo">
<strong>Grower</strong><br />
<a data-role="button" data-theme="e" id="btnGrower" data-bind="click: updateGrowers">
<h3>
<span data-bind="text: GrowerName"></span>
</h3>
<span data-bind="text:GrowerCompany, visible: ShowGrowerCompany" class="block"></span><span data-bind="text: GrowerAddress">
</span>
<br />
<span data-bind="text: GrowerID"></span>
</a>
</div>
@If ViewData("IsDealer") Then
@<div id="BranchInfo">
<strong>Branch</strong> <a data-role="button" data-theme="e" id="btnBranch">
<h3>
<span data-bind="text: BranchName"></span>
</h3>
<span data-bind="text: Company"></span>
<br />
<span data-bind="text: Address"></span>
<br />
<span data-bind="text: ID"></span></a>
</div>
End If
</td>
<td class="splitline">
</td>
<td class="right">
<div class="content-right">
<div id="divGrowerList" style="overflow: auto; height: 450px; padding: 10px;">
<p>Total growers: <span data-bind="text: growers().length"> </span></p>
<ul data-inset="true" data-filter="true" data-bind="foreach: growers" data-role="listview" id="ulGrowerList">
<li><a data-bind="click: $parent.setSelectedClassToGrowerList, attr: {id: growerId}"><span data-bind="text: growerName, attr: {id: growerId}, click: $parent.setSelectedClassToGrowerList" /></a></li>
</ul>
<textarea name="growers" rows="10" data-bind="value: ko.toJSON(growers)"></textarea>
</div>
<div id="divBranchList">
@If ViewData("IsDealer") Then
@Html.Action("MyBranchList2")
End If
</div>
@If ViewData("IsDealer") Then
@<input type="hidden" id="hfFlag" value="1" />
Else
@<input type="hidden" id="hfFlag" value="0" />
End If
</div>
</td>
</tr>
</table>
答案 0 :(得分:0)
没有看到您的_Layout.vbhtml我无法肯定地说,但由于您在每个页面上都运行了javascript,因此您可以在_Layout.vbhtml上使用script
标记
因此,请将其移至Index.vbhtml,或,将其放入<head>
标记,在Layout.vbhtml中使用@RenderSection("Scripts")
并在视图中使用:
@Section "Scripts"
@<script>
// write JS here or reference a file using the src attribute
</script>
End Section
这会将@Section "SectionName"
和End Section
之间的所有内容放在Layout.vbhtml中代替@RenderSection("Scripts")
修改强>
从你的评论到one.beat.consumer我想我看到了你的问题。但是理解我仍在猜测,因为我没有看到你的代码 - 一个大问题,因为你没有提到你使用的是jQuery Mobile 。
常规MVC4 Web应用程序和jQuery Mobile应用程序之间存在重大差异。
一个是:使用jQM,您始终位于同一页面上 - 您通过ajax从服务器加载页面,然后将其拆分为<div data-role="page">...</div>
。这解释了为什么如果将特定页面的脚本放在<head>
部分中,jQM将忽略它们。唯一不会被忽略的<head>
部分是原始页面加载的,但并不总是您的主页。
因此,要加载特定页面的脚本,您不能使用MVC Sections将其放在<head>
元素中。您需要在<div data-role="page">
中引用该脚本。 虽然如果你正在缓存你的页面,这只会触发一次,你可能需要绑定到pageshow
,如果你想再次触发(可能刷新视图模型)。
最后,
你说你在你的pageinit
处理程序中应用了你的viewmodel。每当从服务器获取页面并将其注入DOM时,都会调用此方法。
如果你想让你的js远离视图,你可以在_Layout.vbhtml <head>
中引用一个站点范围的js文件(custom.js)并使用:
$(document).on('pageinit', '#PageId', function(event) {
/* do viewmodel stuff here */
});
只要获取带有<div data-role="page">
的{{1}}并将其注入DOM,就会运行此操作。您可以在此处使用任何选择器,因此id="PageId"
可用于在注入.require-vm
的网页时触发。
答案 1 :(得分:0)
您已在_layout
页面中定义了Knockout ViewModel。
如果您打算在所有页面上使用此视图模型,这很好,但听起来您不想这样做。将其移动到特定的操作视图中以隔离它。
在您对Sethi的上述评论中,您提到javascripts在您执行此操作时不起作用...这可能是因为您在布局和视图中放置了脚本标记。我敢打赌你正在尝试在加载knockout.js之前构建视图模型。
良好做法:
在您的布局中,将脚本标记放在页面底部,就在</body>
关闭标记之前...关闭之前的最后一个标记应该是您的RenderSection()
调用设置。
现在,您可以在视图中的任何位置定义此脚本部分,并确保它将在您的框架脚本之后发生 - 例如。 jQuery,Knockout等。
另外,请记住使用jQuery时,最好使用$.ready()
来确保脚本仅在加载DOM后运行。