简体   繁体   中英

Using AngularJs Service in more than one controllers

I am struggling with angular here. What I learned is that factory and service functions of a module create only one instance of an object associating properties ( functions and variables) with it. And that that instance is available throughout the controllers of the application.

In my app I have created a service module userAngService as follows:

var ser = angular.module('userAngService',[]);

ser.service('userAngService',['$cookies','$location','$http','$log','$rootScope',function($cookies,$location,$http,$log,$rootScope){
    this.user = {};
    $rootScope.username = {};
    $rootScope.user = {};

    /*this.loadUserData = function(username){
        return $http({
            method: 'GET',
            url: 'http://localhost:7070/storyBoard/webapi/profiles/'+username
        }).success(function(data){
            user = data.data;
            //return user;
        });
    };*/

    this.login = function(val){
        return $http({
            method: 'GET',
            url: 'http://localhost:7070/storyBoard/webapi/stories?username='+val.username+'&password='+val.password
        }).then(function(data){
            if(data.data==="Success"){
                $rootScope.username = val.username;
                $cookies.put("username", val.username);
                $http({
                    method: 'GET',
                    url: 'http://localhost:7070/storyBoard/webapi/profiles/'+val.username
                }).success(function(data){
                    console.log(data);
                    this.user = data;
                    console.log(this.user);
                });
                $location.path("/home");
            }else{
                window.alert('Wrong username or password');
            }
        });
    };

    this.logout = function(){
        $rootScope.user.username = "";
        $cookies.remove("username");
        $location.path("/Diary");
    };

    this.addToShelf = function(wsPublish){
        wsPublish.author = $rootScope.user.username;
        return $http({
            method: 'POST',
            url:'http://localhost:7070/storyBoard/webapi/stories',
            data: wsPublish
        }).then(function(data){
            this.user.stories.push(data.data);
        });
    };
}]);

It contains 3 functions and private variable this.user and 2 rootScope variables $rootScope.username & $rootScope.user . Our concerned function is this.login() function here.

Now,

To use this service module I created a module AllControllers :

 var app = angular.module('AllControllers',['userAngService']);

and I associated 2 controllers with it.

First controller:

app.controller('LoginFormController',['$cookies','$rootScope','$log','$scope','userAngService','userBean',function($cookies,$rootScope,$log,$scope,userAngService,userBean){

    $scope.login = function(val){
        userAngService.login(val);
    };

    $scope.logout = function(){
        userAngService.logout();
    };

    $scope.publishGroup = function(obj){
        userBean.publishGroup(obj);
    };
}]);

*This controller is injected with dependency of userAngService and it's login() function delegates a call to login() function of userAngService service

The login() function in userAngService changes its private variables properties. Which then I am trying to use in another controller and that's where all the problem is. When I am logging the returned promise data in userAngService itself, it is logging successfully but when I try to access in another controller, it just logs an empty object

Second Controller (from where accessing the service's private variables) :

 app.controller('ReachController',['$cookies','$scope','$rootScope','userAngService',function($cookies,$scope,$rootScope,userAngService){
    $scope.user = {};
    $scope.username = {};

    $scope.user = userAngService.user;
    console.log(userAngService.user);
    $scope.username = $cookies.get("username");

    /*userAngService.loadUserData($scope.username).then(function(data){
        $scope.user = data.data;
        console.log($scope.user);
    });*/

    console.log($scope.user);
    console.log($rootScope.user);

    $scope.logout = function(){
        userAngService.logout();
    };

    $scope.addToShelf = function(wsPublish){
        userAngService.addToShelf(wsPublish);
    };
}]);

Well an empty object can only mean that the object properties are defined to null and are not updated by login() function of service. However, in userAndService withing success callback;

console.log(data);
this.user = data;
console.log(this.user);

these lines of code successfully log returned data, while in ReachController or Second Controller 's lines;

$scope.user = userAngService.user;
...
console.log($scope.user);

logs this to console:

Object {}

There are no errors so code is right but then something wrong conceptually I guess. Please help!

if you want to return a data use factory instead of service.

Service always returns a methods with data.

console.log(data);
this.user = data;
console.log(this.user); 

"this" object is for local scope of Success function. it will overridden service "this" object.

My guess is that the problem is in the same naming of service and parent module - userAngService . Try renaming module to userAngServiceModule . I would expect angular's DI to get confused whether you are referring to module or service when you add dependency to userAngService .

The this context inside a promise .then handler is not the same as the this context of a service.

app.service("myService", function($http) {
    var myService = this;
    this.data = {};

    this.fetch = function(url) {
        //return promise 
        return (
            $http.get(url).then (function onFulfilled(response) {
                //Won't work
                //this.data = response.data;

                //Instead use the binding
                myService.data = response.data;
                //Return data for chaining
                return myService.data;
            }).catch (function onRejected(response) {
                console.log(response.status);
                //throw to chain rejection
                throw response;
            });
        );
    };
});

The this context in the onFulfilled function is not the same as the this context of the service. Instead bind the this context of the service to a variable and use that variable in the onFulfilled function of the promise .then method.

Also be aware that this.data variable of the service gets set in the future sometime after the XHR by the $http service completes. To be sure the data is available, use the promise that the fetch function returns.

In the controller

var promise = myService.fetch(url);

promise.then (function onFulfilled(data) {
    $scope.data = data;
}).catch( function onRejected(errorResponse) {
    console.log(errorResponse.status);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM