0

I've read in other SO answers that code that doesn't manipulate the view should be accessed via services. However, I have a function that I want to share over several Angular controllers, which accesses both $scope, $rootScope and $location:

    $scope.selectBatch = function (id) {
        if (!id) {
            $scope.batchSelected = false;
            $rootScope.job = false;
            $scope.data = allData;
            $location.path('/', false);
        } else {
            $scope.batchSelected = id;
            $rootScope.job = {'BatchId': id};
            var arr = [];
            for (var i = 0; i < allData.length; i++) {

                if (String(allData[i].BatchId) === String(id)) {
                    arr.push(allData[i]);
                }
            }

            $scope.data = arr;
            $rootScope.go(id, 'batch');
        }
    };

Ideally, in each controller I'd like to do something like:

 $scope.selectBatch = services.selectBatch($scope, $rootscope, $location);

to load in this function from a service, although this feels "non-angular".

What's the "Angular" / MVC way of injecting this sort of function into multiple controllers?

JVG
  • 20,198
  • 47
  • 132
  • 210
  • How do the controllers differ? Could you just re-use the one controller? – Phil Mar 29 '16 at 01:29
  • No, the controllers are very different in terms of the data they bring in and how it's handled. There are one or two functions like this that are shared across all controllers though. – JVG Mar 29 '16 at 01:32
  • Doesn't really make sense to modify $scope primitives before doing a redirect. Should never need to pass `$scope` into service/factory either – charlietfl Mar 29 '16 at 01:38
  • This is what angular services were made for. So you could share data among controllers. You should keep that function in a service and inject that service into everyone of the controllers. – Luis Deras Mar 29 '16 at 01:38
  • @charlietfl I get what you mean, although that's not a redirect - it's actually an extension of `$location.path()` to allow a rewrite of the URL without refreshing the page / changing controller. A little hackier than I like but in the context of the app it makes sense. – JVG Mar 29 '16 at 01:41
  • @ggderas So are you saying that what I've done in the example at the bottom is the correct way to do it? (i.e. passing `$scope`, `$rootScope` and `$location` to the service) – JVG Mar 29 '16 at 01:42
  • @Jascination yes. Because you want to get access of the controllers from within a service. Or am I wrong? Although the flow proposed by Angular MVC is the other way around. Share data among controllers using services. – Luis Deras Mar 29 '16 at 01:44
  • @Jascination but so you're not sending the $scope and $rootScope parameters? – Luis Deras Mar 29 '16 at 02:15
  • @ggderas I wrote an answer below, feel free to edit / add your own if there's a better way to do it :) – JVG Mar 29 '16 at 02:18

2 Answers2

0

From the comments on this question it appears the correct answer is to do it like this:

1. Create a service that returns a function

angular.module('myApp.services', []).service('shared', ['$location', function ($location) {

   this.selectBatch = function($rootScope, $scope){
      return function(id){
         // Do stuff with $location, id, $rootScope and $scope here
      }
   }

}]);

2. Inject the service and associated functions into your controllers

.controller('myCtrl', ['shared', '$scope', '$rootScope'
    function (shared, $scope, $rootScope) {

        $scope.selectBatch = shared.selectBatch($rootScope, $scope);

}]);

You can then call this function using $scope.selectBatch(id) and it works as expected.

Happy to consider other answers if there are "better" ways to achieve this.

JVG
  • 20,198
  • 47
  • 132
  • 210
0

Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.

You can use services to organize and share code across your app

Be aware that sending $scope as parameter to a service is not a good idea. Instead you could send the parameters the function needs in order to process something. This way your service could be more reusable.

Check this SO Question: Injecting $scope into an angular service function()

Ideally you could write a shared service like this:

app.factory('sharedService', ['$location', function($location)
{
    var sharedService = {};

    sharedService.selectBatch  = function(batchSelected, job, data, id)
    {
        //Do something with batchSelected, job, data, id parameters
    };

    return sharedService;
}]);

Then all your controllers could look like this

app.controller('myCtrl', ['sharedService', function(sharedService)
{

    $scope.batchSelected;
    $scope.job;
    $scope.data;
    $scope.id;

    $scope.selectBatch = sharedService.selectBatch($scope.batchSelected, $scope.job, $scope.data, $scope.id);
}]);

NOTE

You don't have to send the $location parameter either, since you could inject it in your shared service.

Community
  • 1
  • 1
Luis Deras
  • 1,239
  • 2
  • 19
  • 48