3

Is there an easier way to get a parent object's 'subscribe' to fire with changes to any of the lower level observables?

The following code and sample fiddle are working, but it requires me to duplicate my masterOptions in optionSet. This smaller version is manageable, but my masterOptions set can become quite large which will make maintenance of both masterOptions and optionSet difficult and error-prone.

Sample jsfiddle found here: 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>

Script:

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());

I would rather NOT have to recreate the masterOptions as optionSet, but I don't see how I can have a single subscribe fire when any of the lower level observables change.

4

2 回答 2

2

在您计算的 masterOptions 上调用 ko.toJS 可以解决问题:

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

[jsfiddle]

这对结构中的每个可观察对象产生了依赖关系。此外,添加到其中的任何可观察对象都将作为依赖项包含在内。

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

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

于 2014-05-27T15:33:19.643 回答
0

您可以尝试使用ko 映射插件。我不确定我的解决方案是最好的,但你可以看看:

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

于 2014-05-24T06:55:15.483 回答