我是Javascript和Knockout的新手.我坚持要绑定我的ViewModal.以下是ViewModal和View在同一个Index.chtml文件中时正在运行的代码:
ProfilesViewModel = function () { self = this; self.ProfileId = ko.observable(""); self.FirstName = ko.observable(""); self.LastName = ko.observable(""); self.Email = ko.observable(""); self.Image = ko.observable(""); self.Phone = ko.observable(""); // Public data properties self.Profiles = ko.observableArray([]); GetAllProfiles(); function GetAllProfiles() { // alert("here"); $.ajax({ type: "get", url: "@Url.Action("getAllProfiles")", contentType: "application/json; charset=utf-8", dataType: "json", success: function (data) { self.Profiles(data); //Put the response in ObservableArray }, error: function (error) { alert(error.status + "<--and--> " + error.statusText); } }); }; }
但当我将我的ViewModal移动到另一个Js文件时,如下 Modal.js代码:
ProfilesViewModel = function () { self = this; self.ProfileId = ko.observable(""); self.FirstName = ko.observable(""); self.LastName = ko.observable(""); self.Email = ko.observable(""); self.Image = ko.observable(""); self.Phone = ko.observable(""); // Public data properties self.Profiles = ko.observableArray([]); }; ko.applyBindings(new ProfilesViewModel()); // This makes Knockout get to work
并在Index.cshtml中:
var obj = new ProfilesViewModel(); GetAllProfiles(); function GetAllProfiles() { // alert("here"); $.ajax({ type: "get", url: "@Url.Action("getAllProfiles")", contentType: "application/json; charset=utf-8", dataType: "json", success: function (data) { obj.Profiles(data); //Put the response in ObservableArray }, error: function (error) { alert(error.status + "<--and--> " + error.statusText); } }); }
绑定不成功.我不知道我在哪里做错了.请咨询.
如果建议使用更好的模块化方法,我也会感激.
在您的外部JS中,您ko.applyBindings
使用已ProfileViewModel
定义的内联调用,但稍后在调用时GetAllProfiles
,您正在使用另一个ProfileViewModel
未绑定的实例.
你在这里遇到了很多问题.既然你是新手,你需要知道的最重要的事情就是命名空间.在全局范围内定义变量和函数是危险的.您希望将自定义命名空间中的所有代码封装到应用程序中.这很简单:
var MyAwesomeNamespace = MyAwesomeNamespace || {};
无论你喜欢什么,都可以调用它,但是尝试选择一些对你或你的应用程序来说很独特的东西 - 这是别人不太可能使用的.然后,一旦你有了,只需将事物定义为命名空间的属性:
MyAwesomeNamespace.SomeFormerlyGlobalVariable = 'foo';
然后,在处理像AJAX这样的事情时,最好创建一个实用程序/服务对象来保存该逻辑.如果它仅适用于此页面,则约定是在页面的主要对象或目的之后命名.根据您的情况,我会做以下事情:
MyAwesomeNamespace.ProfileDisplay = function () { var _getAllProfiles = function () { ... }; return { GetAllProfiles: _getAllProfiles } })();
以上称为闭包.我们设置ProfileDisplay
了一个匿名函数,它立即被调用(()
最后).这将产生ProfileDisplay
函数返回值的值,因此您现在可以拥有私有和公共成员,有点像更传统的面向对象类.函数未返回的任何内容都是私有的,代码的其余部分无法访问,而返回的对象中的项目是公共的,并且可用作其余代码可用的API.现在你可以用你的AJAX调用:
MyAwesomeNamespace.ProfileDisplay.GetAllProfiles();
但是,我们现在再添加一个回调参数.无论您是否需要对此AJAX端点进行多次调用,都可以将其概括为一般,以便在需要时可以在不同的场景中使用.AJAX调用将始终是相同的,但成功时发生的是上下文,因此这是我们将抽象的部分.在这里,我也将切换到不那么冗长$.getJSON
,因为你没有做任何疯狂的事情来实际需要 $.ajax
.
MyAwesomeNamespace.ProfileDisplay = function () { var _getAllProfiles = function (callback) { $.getJSON('/api/profiles') .done(callback) .fail(function (jqXHR, textStatus, error) { alert(error.status + "<--and-->" + error.statusText); }); }; return { GetAllProfiles: _getAllProfiles } })();
那很简单.现在,您有了一个可重用的方法来获取配置文件.我还投入了另一个名为"承诺"的功能.这是一个自己的话题,我鼓励你自己进一步调查.我只会说虽然这里使用非常简单,但它们非常强大.
最后,在命名空间中以相同的方式定义视图模型.但是,这里我们将定义将处理AJAX响应的回调,因为viewModel本身可以访问自身,这使得它很容易获得Knockout可观察量.
MyAwesomeNamespace.ProfileViewModel = function () { var self = this; self.UpdateProfileArray = function () { MyAwesomeNamespace.ProfileDisplay.GetAllProfiles(function (result) { self.Profiles(result); }); }); ... }
最后,我们将使用初始化方法和连接页面事件的方法来扩展我们的实用程序对象:
MyAwesomeNamespace.ProfileDisplay = function () { var _init = function () { var viewModel = MyAwesomeNamespace.ProfileViewModel(); ko.applyBindings(viewModel); _wireEvents(viewModel); // the initial fetch of profiles list on page load viewModel.UpdateProfilesArray(); }); var _wireEvents = function (viewModel) { // Imagining a button that can be clicked to refresh list of // profiles on demand to illustrate how you're wire everything // together here. $('#RefreshProfilesButton').on('click', viewModel.UpdateProfilesArray); }); ... // See, here we're not returning `_wireEvents` because public // access is not needed return { Init: _init, GetAllProfiles: _getAllProfiles } });
所有这些代码都可以安全地放在外部JS中.最后,有了这个,您在实际视图中所需要的只是:
<script src="/path/to/external.js"></script> <script> $(document).ready(function () { MyAwesomeNamespace.ProfileDisplay.Init(); }); </script>
更清洁.
最后一句话是关于你的AJAX方法的URL.在这里,我对其进行了硬编码,以免分散讨论的注意力,但最好依靠路由框架来为您提供信息.我们无法从外部javascript文件中访问它,这意味着我们必须通过内联javascript传递它.这是另一个拥有命名空间有助于保持秩序的领域.所以,首先我们要初始化我们的命名空间:
var MyAwesomeNamespace = MyAwesomeNamespace || {};
您想先将该行添加到您的所有javascript中.它确保如果命名空间尚未初始化,则将其初始化为空对象.=
由二进制值分隔的组合||
,实际上意味着,如果已经设置了此对象,则将其设置为自身(基本上什么都不做),或者如果没有,则将其设置为空对象.
然后,我们可以在命名空间中设置一个变量来保存我们的URL.(实际上,您可能希望进一步设置URLs
对象或命名空间之外的东西,然后指定其中的URL变量,只是为了使事情变得更加整洁.)
MyAwesomeNamespace.GetAllProfilesURL = '@Url.Action("getAllProfiles")';
然后修改_getAllProfiles
方法:
var _getAllProfiles = function (callback) { $.getJSON(MyAwesomeNamespace.GetAllProfilesURL) .done(callback) .fail(function () { ... }); }