7

I'm pretty new to the whole AngularJS world and how it works, however I am struggling to get it working as expected. I know that its something to do with the way I am using $http.get() and trying to assign the variables back to my controller, but I just can't figure it out.

Using $scope instead of this I can get it working, however if possible, I'd prefer to be using this so I can use "controller as"

Code:

app.controller('ctrlSuppliers', function($http){

    this.supplierList = {};

    $http.get("http://some_url_here")
            .success(function(response) {  this.supplierList = response.records;})
            .error(function() { this.supplierList = [{supplier_id: 0, supplier_name: 'Error Getting  Details'}];});
});

From this example, I cannot then access any results from the $http.get request from within the supplierList within the HTML page (i.e. {{ supplier.supplierList[0].supplier_name }} doesnt display any results)

I know that if I change the controller to $scope I can get access to that data (although not using the same format as above), and I also know the data is being populated by using console.log(this.supplierList) inside the .success call.

I also know that the reason its not working is because the context of this changes from within the controller to within the $http.get call.

So my question is this: How do you get access to the results from a $http.xxx call using this instead of scope? I have read a few different sources on it, but most talk about using $scope and promises. I've not found any that cover using this (or declaring it with var supplier = this). Any help would be much appreciated.

Thanks,

Doug
  • 547
  • 10
  • 23
  • Just a heads-up that $http calls usually don't belong in your controllers! Extract them to a service instead for reusability, stability, and non-gratuitous dependency injection. – Hypaethral May 14 '15 at 16:19
  • @GrumbleSnatch Thanks for that. As I said, I've only just started looking at Angular and haven't had time to look through all the features and functions yet, however knowing about it now will likely save me a lot of time down the track when I eventually discovered them – Doug May 14 '15 at 18:56

5 Answers5

9

Always store a variable reference to this so that you don't have context issues, then use that variable instead of this throughout controller

app.controller('ctrlSuppliers', function($http){
    var vm = this;
    // now can forget using "this" and use variable instead
    vm.supplierList = {};

    $http.get("http://some_url_here") .success(function(response) {
         // no context issues since "vm" is in scope  
         vm.supplierList = response.records;
    });               
});
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • 1
    I am sure I tried that approach last night and it wasn't working for me, however declaring `this` to a variable and referencing that variable is now working. So simple - Thanks so much – Doug May 14 '15 at 16:03
  • 1
    For anyone who is reading this, success is deprecated now. Use .then instead. – Miguel Xoel Garcia Feb 03 '16 at 08:56
2

For $http you have the option of storing your own objects in the configObject which is the optional second argument to $http.get(). This object is then made available to you as it's a property of response.

This technique is especially useful if you're calling $http.get() multiple times in a loop.

pinoyyid
  • 21,499
  • 14
  • 64
  • 115
2

The this variable is tricky in JavaScript. When callback function is executed you won't know what the this is referencing. Unless it's documented somewhere.

You have to use the .bind(this) to attach your own this value to be used in the function.

app.controller('ctrlSuppliers', function($http){
    this.supplierList = {};
    $http.get("http://some_url_here")
            .success(function(response) {
                 this.supplierList = response.records;
            }.bind(this))
            .error(function() { 
                 this.supplierList = [{supplier_id: 0, supplier_name: 'Error Getting  Details'}];
            }.bind(this));
});

See bind manual:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Reactgular
  • 52,335
  • 19
  • 158
  • 208
2

With arrow functions available in ecmascript 6 the problem with this is taken care of and you have less to type. Your example would look like this :

app.controller('ctrlSuppliers', function($http){
    this.supplierList = {};

    $http.get("http://some_url_here")
            .success(response => { this.supplierList = response.records; })
            .error(() => { this.supplierList = [{supplier_id: 0, supplier_name: 'Error Getting  Details'}]; });
});

the result is equivalent to storing this to a variable but more concise.

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
1

I think charlietfl's answer is the correct one, but think a slightly expanded explanation might be helpful.

"this" in javascript refers the the context of the current function call. If you look at your code, you'll see that this is being used in two functions -

app.controller('ctrlSuppliers', function($http){

    //first use of this - used in the context of the controller function
    //In this case, this = the controller
    this.supplierList = {};

    $http.get("http://some_url_here")
            .success(function(response) {  
                //second use of this - used in the context of the http success function callback
                //this will likely not be the controller.  It's value depends on how the caller (the $http framework) invoked the method.
                this.supplierList = response.records;
             })
             ....

Since they are two different functions, they may have completely different contexts, so "this" will refer to different objects (as you are experiencing).

The standard way of dealing with this is to save the call context of the first function for use in the others. @charlietfl's answer is a good way to accomplish this. I've added his code for reference.

app.controller('ctrlSuppliers', function($http){
    var vm = this;
    vm.supplierList = {};

    $http.get("http://some_url_here")
            .success(function(response) {  vm.supplierList = response.records;})
});
Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75