knockoutjs: can we create a dependentObservable fu

2019-01-07 22:23发布

问题:

I have multiple input boxes that I want to hide/unhide based on a selection from user.

I can achieve this by having a separate dependentObservable for each input and in turn making the dependentObservable observe the parent selection.

viewModel.showField1= ko.dependentObservable(function () {
    return viewModel.selectedType() ? IsFeatureVisible(viewModel, "BusinessFieldName1") : false;
}, viewModel
);

viewModel.showField1= ko.dependentObservable(function () {
    return viewModel.selectedType() ? IsFeatureVisible(viewModel, "BusinessFieldName2") : false;
}, viewModel
);

this is kind of tedious to do for each field. Can I bind the elements with a dependentObservable function that can take a parameter? Important thing is it should get triggered when the parent changes

Other option is that when the parent changes, I loop through the elements and hide/unhide but that will require me to map the element id <-> business name of the field.

Current

 <tr data-bind="visible: showField1">
 <tr data-bind="visible: showField2">

Desired

<tr data-bind="visible: showField('BusinessFieldName1')">
<tr data-bind="visible: showField('BusinessFieldName2')">

回答1:

In Knockout, bindings are implemented internally using dependentObservables, so you can actually use a plain function in place of a dependentObservable in your bindings. The binding will run your function inside of a dependentObservable, so any observables that have their value accessed will create a dependency (your binding will fire again when it changes).

Here is a sample: http://jsfiddle.net/rniemeyer/2pB9Y/

html

type "one", "two", or "three": <input data-bind="value: text" /> 
<hr />
<ul data-bind="template: { name: 'itemTmpl', foreach: items }"></ul>

js

<script id="itemTmpl" type="text/html">
    <li data-bind="text: name, visible: viewModel.shouldThisBeVisible(name)"></li>
</script>

var viewModel = {
    text: ko.observable("one"),
    items: [{name: "one"}, {name: "two"}, {name: "three"}],
};

viewModel.shouldThisBeVisible = function(name) {
    return this.text() === name;
}.bind(viewModel);

ko.applyBindings(viewModel);


回答2:

var someOtherViewModel = {
   showField: function(fieldName) {
       return ko.dependentObservable(function () {
           return viewModel.selectedType() ? IsFeatureVisible(viewModel, fieldName) : false;
       }, viewModel);
   }
};

You can create a function like the one above. The function returns a new dependent observable for the specific field name.

Now you can do:

<tr data-bind="visible: someOtherViewModel.showField('Field1')">

Inform me if that code doesn't work - maybe I missed something. Then I'll edit this post.



回答3:

Taking the idea from @Arxisos even further, I came up with this.

self.showField = function (fieldName)
{
    return ko.dependentObservable(function () 
    {
        return this.selectedType() ? IsFeatureVisible(this, fieldName) : false;
    }, this)();
};


标签: knockout.js