RobertPorter
RobertPorter

Reputation: 552

Knockout subscribe scope

Is there any possibility to change the scope of the subscribe in Knockout?

I have something like this:

element =
    {
        type: ko.observable()
        name: ko.observable()
        content: ko.observable()
    }

element.type.subscribe(this._typeChanged.bind(element))

Basically I want to have an access to the object which property I am subscribed to. Binding like in my code does nto work since it binds to the whole VeiwModel and not the object.

Upvotes: 4

Views: 8899

Answers (3)

RobertPorter
RobertPorter

Reputation: 552

Although I get that I may have the wrong approach top this I am also in a stage where I will not be able to do any breaking changes to the app.

I figured out that I could use lodash to help me with this. I ended up using partial function to append the element as a parameter in the subscribe callback:

element.type.subscribe(_.partial(this.typeChanged, element))

or in coffeescript

element.type.subscribe $_.partial @typeChanged, element

Now the chartTypeChanged has 2 parameters on the input instead of one.

Upvotes: -1

JotaBe
JotaBe

Reputation: 39004

The problem is the way in which you're creating your view model. The view model shuld be self-contained, including the functions that operate on it. It should be something like this:

var ViewModel = function() {
    var self = this;
    self.type = ko.observable();
    self.name = ko.observable();
    self.content = ko.observable();
    self.type.subscribe(function(newVal) {
        // here you have access to all the viewmodel properties through self
    });
    return self;
};

This is a constructor using the var self=this; pattern.To use the view model you need to instantiate it, i.e. var vm = new ViewModel(). (You can omit the new).

Of course, you can also define a function, and bind it to self, or receive a callback in the constructor, and bind it to self. In that case, the function implementation will have the view model accesible via this, and not self, which will be undefined inside the function body.

var doSomethignWithVm = function(newVal) {
    // acces viewmodel via this
    // you can also use newVal
};

You modify the constructor to receive this as a callback:

var ViewModel = function(doSomethingCallback) {
    self.type.subscribe(callback.bind(self));
};

This pattern doesn't make much sense because your callback is supposed to have knowledge of your view model. In that case it makes more sense to include the subscription functionality directly inside the model.

EDIT Note: as I've mentioned in a comment to Joel Ramos Michaliszen's answer, both of this codes are equivalent:

self.type.subscribe(callback.bind(self));
self.type.subscribe(callback.bind, self);

You can check that by seeing the source code of subscribable in knockout's gitbhub, in the file knockout/src/subscribales/subscribable.js. If you look for subscribe implementation you'll see this:

subscribe: function (callback, callbackTarget, event) {
    // ...
    boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;

I.e. if you provide a second argument, it's used tob bind the function passed in the firt argument to it.

Upvotes: 1

Joel R Michaliszen
Joel R Michaliszen

Reputation: 4222

Maybe the knockout handle that when you subscribe an observable you can pass 2 parameters the first is the callback and the second is the scope/context, try something like this:

element.type.subscribe(this._typeChanged, element)

The subscribe function accepts three parameters: callback is the function that is called whenever the notification happens, target (optional) defines the value of this in the callback function, and event (optional; default is "change") is the name of the event to receive notification for.

Ref. http://knockoutjs.com/documentation/observables.html

Upvotes: 7

Related Questions