Knockout组件更新可观察不被父视图模型订阅?

时间:2015-06-08 09:46:41

标签: javascript knockout.js publish-subscribe

我编写了一个名为Upload的组件,它允许用户上传文件,然后使用带有这些文件的JSON对象进行报告。在此特定实例中,Upload组件具有来自父视图模型的参数:

<upload params="dropzoneId: 'uploadFilesDropzone', postLocation: '/create/upload', uploadedFiles: uploadedFiles"></upload>

重要性之一称为uploadedFiles。这里的参数绑定意味着我可以在我的组件上引用params.uploadedFiles,并在上传时将.push()个新对象引用到它上面。传递的数据(也称为uploadedFiles)是我父视图模型上的observableArray:

var UploadViewModel = function () {
     // Files ready to be submitted to the queue.
     self.uploadedFiles = ko.observableArray([]);
};

我确实可以确认在我的组件上,params.uploadedFiles是一个observableArray,因为它有一个push方法。在组件上更改此值后,我可以console.log()看到它实际已更改:

params.uploadedFiles.push(object);
console.log(params.uploadedFiles().length); // was 0, now returns 1

问题这个更改似乎没有反映在我的父视图模型中。 self.uploadedFiles()不会更改,但仍会报告长度为0.

无论我在父视图模型中添加self.uploadedFiles.subscribe(function(newValue) {});订阅。

无论我是否在更改后在我的组件上添加params.uploadedFiles.valueHasMutated()方法。

如何从我的组件上的数组中获取更改以反映在父视图模型的数组中?

3 个答案:

答案 0 :(得分:2)

为什么在源已经是一个时创建一个新的可观察数组?您不能指望新对象具有与另一个对象相同的引用:只需将其作为this.uploads = params.uploads传递给组件viewModel。在您的示例的下面修剪版本中,您将看到单击“添加”按钮时两个阵列(在不同上下文中引用的相同阵列)保持同步。

ko.components.register('upload', {
  viewModel: function(params) {
    this.uploads = params.uploads;
    this.addUpload = function() { this.uploads.push('item'); }.bind(this);
  },
  template: [
    '<div><button type="button" data-bind="click: addUpload">Add upload</button>',
    '<span data-bind="text: uploads().length + \' - \' + $root.uploads().length"></span></div>'].join('')
  
});

var app = {
  uploads: ko.observableArray([])
};
ko.applyBindings(app);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: {name: 'upload', params: {uploads: uploads}}"></div>

只有在您的源数组不可观察的情况下,事情变得更复杂并且您需要手动订阅才能更新源,例如。您将在viewModel中插入以下内容:

this.uploads.subscribe(function(newValue) { params.uploads = newValue; });

此外,text绑定中的输出不会为源更新,因为它不可观察。如果由于某种原因我无法想到你会想要2个不同的observableArrays(1个源和1个组件),你仍然可以使用上面的行,但用params.uploads(newValue) <替换功能代码/ p>

答案 1 :(得分:1)

问题可能与此错误有关(待确认):https://github.com/knockout/knockout/issues/1863

编辑1:所以这不是一个错误。您必须打开原始参数才能访问原始的observable。在你的情况下,它将是:

params.$raw.uploadedFiles() //this would give you access to the original observableArray and from there, you can "push", "remove", etc.

问题在于,当你将一个param传递给一个组件时,它会被包装在一个计算的observable中,当你打开它时,你没有原始的observableArray。

参考:http://knockoutjs.com/documentation/component-custom-elements.html#advanced-accessing-raw-parameters

答案 2 :(得分:0)

虽然涉及Parent的Binding属性 - &gt;儿童关系 以这种方式使用绑定

如果要将数据绑定到子属性 data-bind =&#39; BindingName:ParentViewmodel.ChildViewModel.ObservableProperty&#39;

这里似乎你想要在数组中推送任何数据时对子函数进行subcibe,你可以在Length of Observable数组上编写订阅,这可以帮助你捕获你想要的事件。

这可以解决您的问题。