user2815588
user2815588

Reputation:

Getting correct scope in functions (not using that = this)

I am trying to fix a function I have here to be able to use it without using a that = this (or self = this as some like to use). It is a scoping issue but I am not sure how to get around it, and I would like to get in the habit of not using a that = this . So the functions are all in a return (angular factory) and I am having trouble referencing another function . Let me show you what I mean :

  return {
            loadStates: function() {

                     var that = this;
                     //chgeck if is loaded module, then change and fire callback
                     var currentModules = moduleHolder.getModules();
                     if (currentModules[name]) {
                        //works here
                         this.prepState();

                     } else {
                         //module cannot be found check for 5 seconds
                         $log.warn("Requesting " + name + "...");
                         var timeToCheck = true;
                         setTimeout(function() {
                             timeToCheck = false;
                         }, 5000);
                         var check = {
                             init: function() {
                                 check.checkAgain();
                             },
                             checkAgain: function() {
                                 if (timeToCheck) {
                                     if (currentModules[name]) {
                                        //but not here
                                         that.prepState();
                                     } else {
                                         //still doesn't exists
                                         setTimeout(check.checkAgain, 200);
                                     }
                                 } else {
                                     //doesn't exist after 5 seconds
                                     $log.error("Requested module (" + name + ") could not be found at this time.");
                                 }
                             }
                         };
                         check.init();
                     }

                 },
                 prepState: function() {

                 }

             }

So in the top if it finds the currentModule[name] I can use a this.prepState() and it works fine. However inside the timing functions I cannot use the this anything because it is inside a different scope so I have temporarily gotten around this by setting a that = this up top, however I would like see if I could not use this method. How does one get around this without using the that= this? Thanks!

Upvotes: 0

Views: 47

Answers (3)

null
null

Reputation: 7926

It's not a scoping issue. If you want to avoid self = this you can always reference functions by objects. Makes cleaner code and since factories in angular are singletons you're not wasting memory.

angular.module('myApp').factory('myFactory', function ($timeout) {

  var myFactory = {
    loadState: function () {

      $timeout(function () {
        myFactory.check();
      }, 500);

    },
    check: function () {

    },
  };

  return myFactory;

}); 

Upvotes: 0

Vikash
Vikash

Reputation: 714

there are different ways you can do that. One way is to use bind function.you can use

 var checkInitBindFn = check.init.bind(this);
 checkInitBindFn();

Secondly you can use call and apply also.

check.init.call(this);
check.init.apply(this);

Like this you can use this instead of that. Check the complete api doc online...

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1073968

It is a scoping issue...

No, it isn't. this and scope have essentially nothing to do with each other. (For now; ES6's arrow functions will change that.) It's an issue of how the functions are called.

If you pass a function reference to something that will call it later, unless the thing you're passing it to has a way you can use to tell it what to use for this when calling it, your function will get called with this not referring to what you want it to refer to.

You can get a new function reference that will call your original function with the correct this by using Function#bind:

var usesCorrectThis = originalFunction.bind(valueForThis);

So for example, suppose I have:

var check = {
    name: "Fred",
    sayHello: function() {
        console.log("Hi, I'm " + this.name);
    }
};

If I do:

check.sayHello();

All is good: Calling the function as part of an expression retrieving it from a property tells the JavaScript engine to use the object as this during the call.

However, if I do:

setTimeout(check.sayHello, 0);

...that doesn't work right, because when setTimeout calls the function, it doesn't use the right value for this.

So I can use Function#bind to address that:

setTimeout(check.sayHello.bind(check), 0);

More (on my blog):

Upvotes: 2

Related Questions