knockoutjs子对象在父计算机中触发更改

时间:2014-05-16 22:48:04

标签: knockout.js parent subscribe computed-observable

是否有更简单的方法来获取父对象'订阅'如果对任何较低级别的可观测量进行更改而触发?

以下代码和示例小提琴正在运行,但它要求我在optionSet中复制我的masterOptions。这个较小的版本是可管理的,但我的masterOptions集可能会变得非常大,这将使masterOptions和optionSet的维护变得困难且容易出错。

此处的示例jsfiddle:fiddle

HTML:

<div>
    Setting1a: <input data-bind="value: masterOptions.group1.setting1a" /><br />
    Setting1b: <input data-bind="value: masterOptions.group1.setting1b" /><br />
    Setting2a: <input data-bind="value: masterOptions.group2.setting2a" /><br />
    Setting2b: <input data-bind="value: masterOptions.group2.setting2b" /><br />
    <br />
    span1: <span data-bind="text: ko.toJSON(optionSet)"></span><br/>
    <br />
    span2: <span id="mySpan"></span>
</div>

脚本:

var masterOptions = {
    group1: {
        setting1a: ko.observable("value1a"),
        setting1b: ko.observable("value1b")
    },
    group2: {
        setting2a: ko.observable("value2a"),
        setting2b: ko.observable("value2b")
    }
};
var optionSet = ko.computed(function () {
    return {
        group1: {
            setting1a: masterOptions.group1.setting1a(),
            setting1b: masterOptions.group1.setting1b()
        },
        group2: {
            setting2a: masterOptions.group2.setting2a(),
            setting2b: masterOptions.group2.setting2b()
        }
    };
});
optionSet.subscribe(function () {
    //alert("Make some magic happen.");
    $("#mySpan").html($("#mySpan").html() + "more magic. ");
});
var ViewModel = function () {
    return {
        masterOptions: masterOptions,
        optionSet: optionSet
    };
};

ko.applyBindings(new ViewModel());

我宁愿不必将masterOptions重新创建为optionSet,但是当任何较低级别的可观察对象发生变化时,我都不知道如何进行单个订阅。

2 个答案:

答案 0 :(得分:2)

在计算机内部的masterOptions上调用ko.toJS可以解决这个问题:

var optionSet = ko.computed(function () {
    return ko.toJS(masterOptions);
});

[ jsfiddle ]

这会在结构中的每个observable上创建一个依赖项。此外,添加到其中的任何可观察对象都将作为依赖项包含在内。

但是,如果您想直接订阅masterOptions和/或需要更多灵活性,您可以考虑使用我自己编写的这个方便的小插件,用于几乎相同的目的:

https://github.com/ZiadJ/knockoutjs-reactor

答案 1 :(得分:0)

您可以尝试使用ko mapping plugin。我不确定我的解决方案是最好的,但你可以看一下:

HTML

<div>
    Setting1a: <input data-bind="value: masterOptions().group1.setting1a" /><br />
    Setting1b: <input data-bind="value: masterOptions().group1.setting1b" /><br />
    Setting2a: <input data-bind="value: masterOptions().group2.setting2a" /><br />
    Setting2b: <input data-bind="value: masterOptions().group2.setting2b" /><br />
    <br />
    span: <span data-bind="text: json"></span><br/>
    <br />
    span2: <span data-bind="text: magicString"></span>
</div>

JS

var anyData = {
    group1: {
        setting1a: ko.observable("value1a"),
        setting1b: ko.observable("value1b")
    },
    group2: {
        setting2a: ko.observable("value2a"),
        setting2b: ko.observable("value2b")
    }
};

var ViewModel = function (data) {
    var magicString = ko.observable("");

    var masterOptions = ko.computed(function() {
        return ko.mapping.fromJS(data);
    });
    masterOptions.subscribe(function () {
        magicString(magicString() + "more magic. ");
    });

    var json = ko.computed(function() {
        return ko.mapping.toJSON(masterOptions);
    });

    return {
        masterOptions: masterOptions,
        magicString: magicString,
        json: json
    };
};

ko.applyBindings(new ViewModel(anyData));

jsfiddle