0

Following is the code that makes an http request to MyApp's API for user profile data(like name, photo) to update the navbar.

var app = angular.module('MyApp', ['ng']);

app.controller('navBarController', function($scope, $userProfile) {
    $scope.userProfile = $userProfile;
    console.log("$userProfile: " + JSON.stringify($userProfile));

    setTimeout(function() {
        console.log("$userProfile: " + JSON.stringify($userProfile));
    }, 3000);

});

app.factory('$userProfile', function($http) {
    var profile = null;
    $http.
        get('/api/v1/me').
        success(function(data) {
            profile = data;
            console.log("profile after get: " + JSON.stringify(profile));
        }).
        error(function(data, $status) {
            if ($status === status.UNAUTHORISED) {
                profile = null;
                console.log("profile if error: " + JSON.stringify(profile));
            }
        });

    console.log("profile (finally): " +  JSON.stringify(profile));
    return profile;
});

app.directive('navBar', function() {
    return {
        controller: 'navBarController',
        templateUrl: 'templates/nav_bar.html'
    }
});

I am console logging to check for the unexpected results I am getting and the logs are as follows:

profile (finally): null

$userProfile: null

profile after get: {"photo":"http://localhost:3000/img/1023.jpg","name":"Utkarsh Gupta"}

$userProfile: null

The first two log msgs are obvious as $http.get() is asynchronous so the profile is null as defined at the start of the function. But after the $http.get() function returns successfully, the profile var got updated as shown in the third log msg but the $userProfile service continues to be null.

1
  • 1
    $ is reserved for angular specific variables... not a good practice to use $ for user made variables Commented Dec 3, 2016 at 8:54

4 Answers 4

1

Looks like your service is not injected into the controller.

Have you tried it that way?

app.controller('navBarController', ["$scope", "$userProfile", function($scope, $userProfile) {}]

Example here: https://docs.angularjs.org/guide/services

Sign up to request clarification or add additional context in comments.

1 Comment

Also be sure to read John Papa styleguide on how to write Angular. github.com/johnpapa/angular-styleguide/tree/master/a1
1

In your service, you have declared var profile = null; and triggering the $http api call then immediately returning the variable profile which is null at the time of returning and later you are updating the variable once the api got response and you are expecting it should be propagated to the controller which is not the case.

As service is singleton in nature, instance will be created once and never created/updated.

Hence, your code is not a recommended one to use a service. I have updated the code below where service will return a method called load to call the api which is getting triggered from the controller where $scope can be directly assigned with the response data.

var app = angular.module('MyApp', ['ng']);

app.controller('navBarController', function($scope, $userProfile) {
    $userProfile.load().
        success(function(data) {
            $scope.userProfile = data;
            console.log("profile after get: " + JSON.stringify($scope.userProfile));
        }).
        error(function(data, $status) {
            if ($status === status.UNAUTHORISED) {
                $scope.userProfile = null;
                console.log("profile if error: " + JSON.stringify($scope.userProfile));
            }
        });

});

app.factory('$userProfile', function($http) {
    var getProfile = function() {
      return $http.
        get('/api/v1/me');
     };

    //console.log("profile (finally): " +  JSON.stringify(profile));
    return {
       load: getProfile 
    };
});

app.directive('navBar', function() {
    return {
        controller: 'navBarController',
        templateUrl: 'templates/nav_bar.html'
    }
});

Note: Also, please don't use $ prefix to service, variable, controller names as this is reserved to AngularJS and may create conflicts when you use the same name as AngularJS reservered keywords/services.

Comments

1

You need to first fix your services (factory). It needs to return and object. Right now you are just running async code in your service, no way for your controller to use it. Second once you fix your service (look at the code below) you need to create a function to get the user profile. The user profile function needs to return a promise since you are working with async code. Again look at the code below and I hope it helps.

var app = angular.module('MyApp', ['ng']);

app.controller('navBarController', function($scope, $userProfile) {

    $userProfile.get().then(function(response){
        $scope.userProfile = response;
    });

    setTimeout(function() {
        console.log("$userProfile: " + JSON.stringify($userProfile));
    }, 3000);

});

app.factory('$userProfile', function($http) {

    var self = {};

    self.get = getProfile;

    return self;

    function getProfile(){

        var profile = null;

        return $http.get('/api/v1/me')
            .success(function(data) {

                return data.data;

            })
            .error(function(data, $status) {

                if ($status === status.UNAUTHORISED)
                    return profile;

            });

     }
});

Comments

0

Instead of initialising profile as null at the top, you must initialise it as:

var profile = {};

And then tack on to that empty profile object your API returned data like:

$http.
        get('/api/v1/me').
        success(function(data) {
        //like this
            profile.data = data;
        })

In your code, when the $userProfile-service function finishes it returns the profile simply as null. And even after the $http.get request is complete your $userProfile has the same null because now the updated profile variable is not accessible anymore as it is out of scope. But if you initialize and return profile as an object, you can access it even after the function has returned because objects are passed by reference in javascript. You can then access the content of the profile object in your controller the way you are alreday doing because now $userProfile is the same exact profile object that you declared above and not a null anymore and any update on that profile object anywhere in your entire code will be reflected wherever that object is being accessed.

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.