angularjsdependency-injectionangular-servicesobjectinstantiation

How to instantiate a service dynamically?


I have a Utils Service which is very heavy. I Want to use some of the functions defined in it on a particular user action. As this service is heavy I want to instantiate it lazily(on user action).

How do I achieve this?

Service

module.service('Utils', function (dep1, dep2) {
   this.method1 = function () {
      // do something
   }
   // other methods
});

Controller

module.controller('AppCtrl', function ($scope) {
    // I don't want to inject Utils as a dependency.

    $scope.processUserAction = function () {
       // If the service is not instantiated 
       // instantiate it and trigger the methods defined in it. 
    }
});

Markup

<div data-ng-controller="AppCtrl">
    <button data-ng-click="processUserAction()"> Click Me </button>
</div>

Solution

  • You can use $injector service to get services anywhere: https://docs.angularjs.org/api/auto/service/$injector. Inject the $injector into your controller, and whenever you need a service use:

    This worked fine for me, the service is instantiated only on the $injector call, no error thrown.

     angular.module('yp.admin')
    
        .config(['$stateProvider', '$urlRouterProvider', 'accessLevels', '$translateWtiPartialLoaderProvider',
            function ($stateProvider, $urlRouterProvider, accessLevels, $translateWtiPartialLoaderProvider) {
                $stateProvider
                    .state('admin.home', {
                        url: "/home",
                        access: accessLevels.admin,
                        views: {
                            content: {
                                templateUrl: 'admin/home/home.html',
                                controller: 'AdminHomeController'
                            }
                        }
                    });
            }])
        .service('UtilsService', function() {
            console.log('utilsSerivce instantiated');
            return {
                call: function() {
                    console.log('Util.call called');
                }
            };
        })
    
        .controller('AdminHomeController', ['$scope', '$rootScope', 'UserService', '$injector',
            function($scope, $rootScope, UserService, $injector) {
            $injector.get('UtilsService').call();
        }]);    
    

    console gives me this:

    stateChangeStart from:  to: admin.home
    stateChangeSuccess from:  to: admin.home
    utilsSerivce instantiated
    Util.call called
    

    If you want to delay loading the JS you should have a look at the ocLazyLoad Module: https://github.com/ocombe/ocLazyLoad. It addresses all sorts of lazy loading use cases and yours sounds like a good fit for it.