17

In my AngularJS application I am doing the following

$http.get('/plugin/' + key + '/js').success(function (data) {
    if (data.length > 0) {
        console.log(data);
        // Here I would also need the value of 'key'
    }
});

Now I need to access the key value within the success callback, i.e. I need to know which value it had when the get() request has been made.

Any "best practice" how to do so?

PS: I can do the following, but is there a better way?

var key = config.url.split('/')[2];
3
  • 2
    Have you tried accessing it directly? It will be available, try console.log(key) Commented Oct 1, 2013 at 13:02
  • Yes that doesn't work, also that callback is asynchronous, so the value of key could have been changed already when it is being called. Commented Oct 1, 2013 at 13:03
  • 3
    @TeamAIGD -- You should definitely have access to key inside the callback, and if key is going to be changing that much, assign key to a different variable right before the call, then use that variable in the callback. Commented Oct 1, 2013 at 13:06

5 Answers 5

23

Solution 1:

$scope.key = key;
$http.get('/plugin/' + key + '/js').success(function (data) {
    if (data.length > 0) {
        console.log(data, $scope.key);
    }
});

Solution 2 (Updated per Jim Hong's observation in his answer):

$http.get('/plugin/' + key + '/js').success((function(key) {
    return function(data) {
        console.log(key, data);
    }
})(key));
Sign up to request clarification or add additional context in comments.

3 Comments

Second solution works for iteration with callbacks. I used it for this: for(var i = 0; i < somelist.length; i++){ doHttpRequest().callback((function(i){ return function(data, etc) { // Do something with the iterator value } }(i))
The second solution works for me. I've edited it to incorporate the correction mentioned by Jim Hong in his answer below.
.success is deprecated. Use then instead
13

Reference to @geniuscarrier The working solution on my side is

$http.get('/plugin/' + key + '/js').success((function(key) {
    return function(data) {
        console.log(key, data);
    }
})(key));

Since using @geniuscarrier, I'l get

data undefined error

.

1 Comment

Good point. I've edited @geniuscarrier 's answer to correct it - a note to readers who are wondering whats different in your answer and geniuscarrier's second solution. They are now the same.
4

Technically speaking, this is not an AngularJS problem but a feature of javascript

first of all, functions that you defined inside a scope will have access to local variable and parameter of its parent scope

function parent(arg){
   var local
   function child(){
       // have access to arg and local
   }
}

Scope actually works well with the parent-child analogy: if you are the parent and you own a cookie, of cause you are welling to share it with your children...but if you are a kid...your cookie is your cookie, your parent is not allowed to touch it :). In other words, inner scope can access outer scope but it does not work both ways

So you should definitely be able to do:

$http.get('/plugin/' + key + '/js').success(function (data) {
    if (data.length > 0) {
        console.log(data, key); //as long as you can pass it to $http.get as an argument
                                //you can access it here
    }
});

Secondly, because of the event-driven nature of javascript, inner function store references to the outer function’s variables. you probably have heard of this

functions in javascript are objects

local variables and parameters are thus private members of the function:

function ObjectA(){ // define a constructor
    var x = 10      // private variable
    changeX : function(){
                  x = 20   // access and MODIFY a variable of parent scope
              }
}

if you can understand how private variable works in javascript, then you basically understand what closure is. Thus, for call back function, it is very possible that by the time it is triggered, the value of the parent scope variable is already changed. To fix this, you can use an Immediately Invoked Function Expression (IIFE)

$http.get('/plugin/' + key + '/js').success((function(currentKeyValue) {
    return function(data) {
        console.log(currentKeyValue, data);
        // again, currentKeyValue is a REFERENCE to outer function's
        // parameter. However, since String is passed by value in javascript
        // currentKeyValue of outer scope is a DIFFERENT string that has the
        // same value as KEY when it is invoked
    }
})(key)); // immediately invoke the function passing the key as a parameter

Comments

2

Instead of polluting scope or complicating with iif, another cleaner way is to create a callback function and call it with parameters;

var myCallBack = function (key) {
  return function (data) {
    if (data.length > 0) {
      console.log(data, key);
    }
  }
}

$http.get('/plugin/' + key + '/js').success(myCallBack(key));

Comments

2

Phew, I was looking for this answer for so long, but it's good it is here. Just to update it, since legacy promise methods success and error have been deprecated and we should use the standard then method instead.

Solution 2 in @geniuscarrier and @jim-horng answers may be rewritten like this:

$http.get('/plugin/' + key + '/js').then(
    (function(key) {
        return function(data) {
            console.log(key, data);
        }
    })(key),
    function(data) {
        //error handle
    });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.