我开始第二次尝试使用KO创建应用程序,所以虽然我觉得我对库的理解是可以通过的,但我使用它的执行仍然需要工作。我有一个关于视图的复杂模型的问题,它不能代表一个逻辑实体。
给定一个复杂或复合视图模型,其中主视图模型的属性是对象本身:
var mainViewModel = function(data){
var self=this;
self.user = new UserModel();
self.roles = new RolesCollectionModel();
}
function UserModel(data){
var self=this;
self.Name = ko.observable(data.name);
}
function RolesCollectionModel(data){
var self=this;
self.Items = ko.observableArray(data.items);
}
在我看来,KO只识别第一级属性的绑定,即没有可观察到的冒泡'。因此,对于我在子对象上使用数据绑定,似乎我必须将它们声明为可观察对象:
var correctViewModel = function(data){
var self=this;
self.SetUserModel= function(userData) {
this.user = ko.observable(userData);
}
self.SetRoles = function (data) {
this.roles = ko.observableArray(data);
}
}
相应地,在我的html中,如果我想绑定userModel属性的名称:
<input data-bind:'textInput:userModel().name'/>
我的问题是:
我的结论是否正确,可观察到的冒泡&#39;不会发生,这是实现绑定到对象图中几个级别的属性的唯一方法吗?
假设我在1中是正确的,上面的语法对我来说很奇怪。 userModel和name都是可观察的,但为了使我的示例有效,我必须将该对象引用为userModel()。name。我原本希望绑定到 userModel.name 。这里令人困惑,对吗?
**我已对此进行了编辑,以包含我将使用的制定者。我们的想法是,在对&gt; 1调用API之后,顶层模型将被组合/绑定。我这样做是因为它在OO意义上更自然,但是从这个对话看来,我可以在API的响应后明确地设置对象属性,例如:
var topModel = new CorrectViewModel();
$.ajax({...}).done(function(data){
topModel.Users=(new UserModel(data));
})
我可以问使用什么更惯用的风格?
答案 0 :(得分:1)
回答1:是的,你是对的,可观察者不会“冒泡”。
回答2:你必须使用那种语法。
现在可以同时解释1和2:一个observable是一个函数,可以通过参数来调用它来设置它的值,或者输出一个参数来获取它。
当knockout找到绑定表达式时,它会检查它是否是可观察的:
我们来看几个案例:
// 1
var vm = { name: ko.observable(); };
// 2
var vm = { hidden: ko.observable(true); };
// 3
var userModel = ko.observable({
name: ko.observable()
});
在所有这些情况下,如上所述,observables是需要调用以获取或设置其值的函数。
最简单的情况是:text: name
。 Knockout检查name
是否是可观察的,因此ko调用它来获取其值
稍微复杂一点:visible: !hidden()
。在这种情况下,knockout看到!hidden()
它不是一个可观察的,并将其评估为“普通JavaScript”。如果你写了visible: !hidden
,那么knockout也会检查它是不是可观察的,所以它会把它评价为“普通的javascript”,结果总是false
,因为hidden
,没有要调用它的括号是function
,这是一个JavaScript值,而!
将truish值转换为false
。
当在其中存在具有可观察属性的可观察对象时,必须调用外部observable以获取对其中包含可观察对象的对象的访问。在表达式userModel().name
中,括号调用userModel
以获取其中的对象,并引用name
可观察对象。因此,当Knockout检查它是否是可观察的时,它会发现它是一个可观察的并对其进行评估。如果您指定userModel.name
它将是yield undefined
,因为userModel
,而不用括号调用它,是一个没有name
属性的函数。
注1:在敲除中有实用函数来发现某些东西是否是可观察的:ko.isObservable(expr)
,并获得表达式的值,不管它是否是可观察的:{{1 }}
注2A:observable实现为函数,以便在调用它们来设置它们的值时,它们可以通知它们已经更改为所有订阅者。订阅是以原创方式创建的。例如,当您指定绑定ko.unwrap(expr)
时,必须设置文本的代码将订阅text: userModel().name
observable,这意味着只要调用name
,其值就会更改,它会通知该代码,以便它可以更改文本。事实上,你也可以像explicit subscriptions
注2B:某些语言,包括现代风格的JavaScript支持属性。读取或写入属性就好像它是一个简单的变量,但它能够执行一些代码而不是简单地设置或获取值。有一些JavaScript库使用此功能,这使得可以使用更简单的语法,没有括号
答案 1 :(得分:0)
以下是我通常如何构建深层绑定的示例,以便它有效地支持冒泡/多个子视图模型。
假设您是特许经营者,并且您拥有多个您管理的特许经营店/地点。
var vm = {
activate: activate,
user: ko.observable(),
currentFranchiseLocation: ko.observable(),
};
function activate() {
vm.user(LoadYourUserHere().Result);
vm.currentFranchiseLocation(LoadTheInitialLocation().result)
}
function changeLocation() {
loadOtherLocation.done(function (data) {
vm.currentFranchiseLocation(new FranchiseLocationVM(data));
});
}
Html绑定
<div data-bind="with: currentLocation">
<h3 data-bind="text:Name"></h3>
<div data-bind="text:numEmployees"></div>
</div>
这里的魔力实际上是with
关键字。它针对一个可观察的和变化的,重新绑定它的整个子树。同时,它将目标可观察目标的内容展开并别名化到本地范围,这样您就可以进行绑定,例如text:Name
,而不是currentLocation().Name