amin
amin

Reputation: 3852

knockoutjs custum bindings preprocess method & addBindingCallback?

From knockout documentation :

ko.bindingHandlers.<name>.preprocess(value, name, addBindingCallback)

Parameters:

value: ...
name: ...
addBinding: a callback function you can optionally use to insert another binding on the current element. This requires two parameters, name and value. For example, inside your preprocess function, call addBinding('visible', 'acceptsTerms()'); to make Knockout behave as if the element had a visible: acceptsTerms() binding on it.

For example we can have bindings like :

ko.bindingHandlers.live = {
   preprocess: function (str, name, addBindingCallback) {
      addBindingCallback('value', str);
      addBindingCallback('valueUpdate', "'afterkeydown'")
   }
};
// Or
ko.bindingHandlers.log = {
   preprocess: function (str, name, addBindingCallback) {
      addBindingCallback('click', "function(){console.log('test');}");
   }
};

My Question:
Is it possible to pass a variable within the scope of preporcess method to the newly added bindings ?

ko.bindingHandlers.log = {
   preprocess: function (str, name, addBindingCallback) {
      // an object which is not in my viewmodel and context
      var $scoped_obj = get_from_some_external_service(str);
      // i want to pass `$scoped_obj` to the newly added click binding
      addBindingCallback('click', "function(){console.log($scoped_obj);}");
   }
};

Is that possible ? and How ?

Upvotes: 2

Views: 613

Answers (2)

sroes
sroes

Reputation: 15053

The way you're trying it now, you can't, because the click handler is evaluated by a Function, which accepts a string as the function body. The scope is lost at that point.

What you could do is create a static function which you call inside the click handler:

ko.bindingHandlers.log = {
    functions: [],
    preprocess: function (str, name, addBindingCallback) {
        var fnIndex = ko.bindingHandlers.log.functions.length;

        var $scoped_obj = {a: 'b'};
        ko.bindingHandlers.log.functions.push(function() {
            console.log($scoped_obj);
        });
        addBindingCallback('click', "ko.bindingHandlers.log.functions["+fnIndex+"]");
   }
};

See http://jsfiddle.net/fpoeeb7L/

Alternatively you could use ko.toJSON to create the variable inside the click handler:

ko.bindingHandlers.log = {
    preprocess: function (str, name, addBindingCallback) {
        var $scoped_obj = {a: 'b'};
        addBindingCallback('click', "function() { var $scoped_obj = " + ko.toJSON($scoped_obj) + "; console.log($scoped_obj); }");
   }
};

See http://jsfiddle.net/5e5jbuum/

But this won't work if $scoped_obj contains functions.

Upvotes: 4

JotaBe
JotaBe

Reputation: 39045

You can use a self-executing function to create a closure for the scoped variable. Use the closure to create the scoped variable and the function that uses it, and return the function, like so:

preprocess: (function() {
    var $scoped_obj = get_from_some_external_service(str);
    var fn = function(str, name, addBindingCallback) {
       // can use the scoped variable
    }; 
    return fn;
})();  // self-execution

However, take into account Jeff Mercado's comment to your question.

Upvotes: 1

Related Questions