复杂的KnockoutJS视图模型

时间:2015-10-23 16:26:11

标签: knockout.js

我开始第二次尝试使用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'/>

我的问题是:

  1. 我的结论是否正确,可观察到的冒泡&#39;不会发生,这是实现绑定到对象图中几个级别的属性的唯一方法吗?

  2. 假设我在1中是正确的,上面的语法对我来说很奇怪。 userModel和name都是可观察的,但为了使我的示例有效,我必须将该对象引用为userModel()。name。我原本希望绑定到 userModel.name 。这里令人困惑,对吗?

  3. **我已对此进行了编辑,以包含我将使用的制定者。我们的想法是,在对&gt; 1调用API之后,顶层模型将被组合/绑定。我这样做是因为它在OO意义上更自然,但是从这个对话看来,我可以在API的响应后明确地设置对象属性,例如:

    var topModel = new CorrectViewModel();
    $.ajax({...}).done(function(data){
        topModel.Users=(new UserModel(data));
    })
    

    我可以问使用什么更惯用的风格

2 个答案:

答案 0 :(得分:1)

回答1:是的,你是对的,可观察者不会“冒泡”。

回答2:你必须使用那种语法。

现在可以同时解释1和2:一个observable是一个函数,可以通过参数来调用它来设置它的值,或者输出一个参数来获取它。

当knockout找到绑定表达式时,它会检查它是否是可观察的:

  • 如果它是一个可观察的,淘汰赛“调用”它,以获得它的价值
  • 如果它不是可观察的,则敲除会将代码评估为“普通JavaScript”

我们来看几个案例:

// 1
var vm = { name: ko.observable(); };
// 2
var vm = { hidden: ko.observable(true); };
// 3
var userModel = ko.observable({
   name: ko.observable()
});

在所有这些情况下,如上所述,observables是需要调用以获取或设置其值的函数。

  1. 最简单的情况是:text: name。 Knockout检查name是否是可观察的,因此ko调用它来获取其值

  2. 稍微复杂一点:visible: !hidden()。在这种情况下,knockout看到!hidden()它不是一个可观察的,并将其评估为“普通JavaScript”。如果你写了visible: !hidden,那么knockout也会检查它是不是可观察的,所以它会把它评价为“普通的javascript”,结果总是false,因为hidden,没有要调用它的括号是function,这是一个JavaScript值,而!将truish值转换为false

  3. 当在其中存在具有可观察属性的可观察对象时,必须调用外部observable以获取对其中包含可观察对象的对象的访问。在表达式userModel().name中,括号调用userModel以获取其中的对象,并引用name可观察对象。因此,当Knockout检查它是否是可观察的时,它会发现它是一个可观察的并对其进行评估。如果您指定userModel.name它将是yield undefined,因为userModel,而不用括号调用它,是一个没有name属性的函数。

  4. 注1:在敲除中有实用函数来发现某些东西是否是可观察的:ko.isObservable(expr),并获得表达式的值,不管它是否是可观察的:{{1 }}

    注2A:observable实现为函数,以便在调用它们来设置它们的值时,它们可以通知它们已经更改为所有订阅者。订阅是以原创方式创建的。例如,当您指定绑定ko.unwrap(expr)时,必须设置文本的代码将订阅text: userModel().name observable,这意味着只要调用name,其值就会更改,它会通知该代码,以便它可以更改文本。事实上,你也可以像explicit subscriptions

    那样Aurelia

    注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