what is the scope of a service in angularjs?

2019-09-10 13:02发布

I'm trying angularjs for the first time and created a service that I use to make ajax calls to my application API and retrieve a paginated list. I called it "GridService". The service is injected into a controller and everything works great! Until I tried to use the same service twice inside two different controllers on the same page. To my horror, the second instance of the service overwrites the first (doh)

For example; I render two partials as follows :

        <div id="location_areas" class="container tab-pane fade" ng-controller="areasController" ng-init="initialise()">
            @include('areas._areas')
        </div>
        <div id="location_people" class="container tab-pane fade"  ng-controller="peopleController" ng-init="initialise()">
            @include('people._people')
        </div>

and I inject the service into a controller as follows and link to the service properties

angular.module('areasController', [])

.controller('areasController', function($scope, $attrs, $http, AreaService, GridService, HelperService) {

$scope.areas = function() { return GridService.getListing() }
$scope.totalPages = function() { return GridService.getTotalPages() }
$scope.currentPage = function() { return GridService.getCurrentPage() }
$scope.columns = function() { return GridService.getColumns() }

Lastly, my abbreviated service is as simple as

angular.module('gridService', [])

.provider('GridService', function($http) {

var columns = {};
var filters = {};
var listing = [];
var totalPages = 0;
var range;
var currentPage = 1;

return {

    /**
     * Get the requested data (JSON format) from storage then populate the class properties which
     * are bound to equivalent properties in the controller.
     *
     * @return void
     */
    list : function(url,pageNumber,data) {

        url = url+'?page='+pageNumber;

        for (var key in data) {

            if( angular.isArray( data[key] ) )
            {
                angular.forEach( data[key], function( value ) {
                    url = url+'&'+key+'[]='+value;
                });
            }
            else
            {
                url = url+'&'+key+'='+data[key];
            }
        }

        $http({ method: 'GET', url: url })
        .then(function(response) {
            listing             = response.data.data;
            totalPages          = response.data.last_page;
            range               = response.data.last_page;
            currentPage         = response.data.current_page;
            // Pagination Range
            var pages = [];

            for(var i=1;i<=response.data.last_page;i++) {          
                pages.push(i);
            }

            range = pages; 
        });
    },

Obviously I have boobed (doh). Is it possible to create this scenario or have I misunderstood angularjs architecture?

标签: angularjs
1条回答
够拽才男人
2楼-- · 2019-09-10 13:43

Please update your question with the relevant code for your service. Services in Angular are by definition Singletons. They should not have any private state. If they do have state, it should be state that is means to be shared between two controllers.

If you are just making $http requests in your service, it should just return the promise to the calling controllers -- not causing any "overlap".

UPDATE

It looks like you a missing a few lines from your service. It looks like it contains columns, filters, etc.

So this is the problem, it is a singleton. What you should do it break it up into two different classes, the network layer that still makes the AJAX call to get the data -- and a factory that returns a new instance of your Grid configuration.

gridFactory.$inject = ['$http'];
function gridFactory($http) {

    return function(url, pageNumber, data) {

        // put your for (var key in data) logic here...

        return new Grid($http);
    }

}

function Grid($http) {

   var self = this;

   $http({ method: 'GET', url: url })
    .then(function(response) {

       self.listings = data.listings;
       self.totalPages = data.total_pages;
       ... 
       // put your grid config here following this pattern, attaching each to 
       // the 'self' property which is the prototype of the constructor.

  }
}

So now the factory will return a new instance of the 'Grid' object for every time you call the factory. You need to call the factory like gridFactory(url, pageNumber, data);

查看更多
登录 后发表回答