在Knockout中访问子视图模型

时间:2015-10-30 20:50:57

标签: knockout.js components viewmodel parent children

有没有办法从任何父母访问子视图模型?我的用例是我有一些自定义的淘汰组件。我在单独的文件中有每个组件的基本定义。我希望能够以不同的方式自定义它们,具体取决于它所使用的站点的哪个部分。这可能吗?有很多关于如何从孩子访问父视图模型但没有相反的文档。

所以我希望能够做到这样的事情:

parentViewModel.someChildModel.someProperty(someValue);

1 个答案:

答案 0 :(得分:4)

我发现这样做的方法是让父虚拟机构建子虚拟机,然后将子虚拟机作为参数注入子组件,方法是将子节点定义为:

ko.components.register("child", {
    viewModel: {
        createViewModel: function(params, componentInfo) {
            return params.viewModel;
        }
    },
    template: {
        element: 'child-template'
    }
});

子组件使用createViewModel函数,而不是定义特定的构造函数或实例,该函数使用" viewModel" component param作为viewmodel。 (为安全起见,可以在这里检查是否提供了视图模型,并且它是预期的类)

然后,父虚拟机可以简单地构建子虚拟机,因此可以完全访问它们及其属性。 (例如self.child = new ChildVM()

最后,模板必须实际将ViewModel提供给子组件:

<child params="viewModel: child"></child>

它涉及一些样板,但它是我发现从父母到孩子沟通的最佳方式。

完整示例:

&#13;
&#13;
function ParentVM() {
    var self = this;    

    self.message = ko.observable();

    var callback = function (message) {
        self.message(message);
    }

    self.children = ["foo", "bar"].map(function (text) {
        return new ChildVM(text, callback);
    });
}

function ChildVM(text, callback) {
    var self = this;

    self.text = text;

    self.onClick = function () {
        callback(text + " clicked");   
    }
}

vm = {};

ko.components.register("parent", {
    viewModel: ParentVM,
    template: {
        element: 'parent-template'
    }
});

ko.components.register("child", {
    viewModel: {
        createViewModel: function(params, componentInfo) {
            return params.viewModel;
        }
    },
    template: {
        element: 'child-template'
    }
});

ko.applyBindings(vm);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<parent></parent>

<template id='parent-template'>
  <!-- ko foreach: children -->
  <child params="viewModel: $data"></child>
  <br />
  <!-- /ko -->
  <span data-bind="text: message"></span>
</template>

<template id='child-template'>
  <span data-bind="
        text: text,
        click: onClick
    "></span>
</template>
&#13;
&#13;
&#13;