Update is not called in knockout.js custom binding

2019-08-04 23:05发布

Here is a code snippet

<!DOCTYPE html>

<html>
<body>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>

    <div>
        <div data-bind="yourBindingName: someValue ">
        </div>
        <button data-bind="click: clickme">Click me!</button>
    </div>

    <script type="text/javascript">
        ko.bindingHandlers.yourBindingName = {
            init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
                console.log("init");
            },
            update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
                console.log("update");
            }
        };

        function ViewModel() {

            this.someValue = ko.observable('test');

            this.clickme = function () {
                console.log('clickme');
                this.someValue('');
            }
        }
        ko.applyBindings(new ViewModel());
    </script>

</body>
</html>

After clicking the "Click me!" button there is only 'clickme' in console and never 'update'. I expect the update function to be fired every time its bound value changed.

标签: knockout.js
1条回答
干净又极端
2楼-- · 2019-08-05 00:04

It does log an "update", but before you click the button. Knockout has run it once already, and whilst running has checked which observables your binding handler makes use of. Since you don't access valueAccessor (or anything else) within it, it knows that it doesn't need to call update on your binding handler when someValue changes - it would be a waste of processing time. If you update your binding handler to use it, it will be called when someValue changes, ie the first time you click the button:

ko.bindingHandlers.yourBindingName = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("init: " + valueAccessor()());
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("update: " + valueAccessor()());
    }
};

Here's a demo:

ko.bindingHandlers.yourBindingName = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("init: " + valueAccessor()());
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("update: " + valueAccessor()());
    }
};

function ViewModel() {
    
    this.someValue = ko.observable('test');
    
    this.clickme = function () {
        console.log('clickme');
        this.someValue('');
    }
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
(Open your dev tools to view the console)
<div data-bind="yourBindingName: someValue ">
</div>
<button data-bind="click: clickme">Click me!</button>

查看更多
登录 后发表回答