вторник, 12 август 2014 г.

Dynamic routing in AngularJS App.config method.

Some time ago I had a work task required to make dynamic routing in App.config method of AngularJS application. Initially I wanted to do something like this:

someApp.config(['$routeProvider', '$httpProvider', 
    '$compileProvider', 'settings',
    function ($routeProvider, $httpProvider, 
        $compileProvider, settings) {

        var $http = angular.injector(['ng']).get('$http');
        var $q = angular.injector(['ng']).get('$q');
        var isUserLogged = $q.defer();

        $http.get(settings.apiUri + settings.loginStatus).
          success(function (data) {
            if (data.status == "NOT_LOGGED") {
                isUserLogged.reject();
            } else {
                isUserLogged.resolve();
            }
        });

        isUserLogged.promise.
          catch(function () {
             $routeProvider.
                 when('/home', {
                     templateUrl: 'partials/home.html',
                     controller: 'HomeController'
                 }).
                 otherwise({
                 redirectTo: '/home'
             });
        });

        isUserLogged.promise.
         then(function () {
            $routeProvider.
                when('/accountsettings', {
                    templateUrl: 'partials/accountsettings.html',
                    controller: 'AccountSettingsController'
                }).
                otherwise({
                    redirectTo: '/accountsettings'
                });
        });
    }]);

But routing did not work because .config method behaves as synchronous. When I remove the http query and promice logic everything worked perfectly. I asked a question in stackoverflow, but there was no answer. After reading the documentation and digging I came to the decision that satisfy me. I did a manual bootstrapping of the application. First I make request to determine whether the user is logged or not. Then I trigger custom event listener whose call .config method of application and do routing in accordance whether the user is logged or not. Below is the code of the decision to which I got (with abbreviations).

angular.element(document).one("userStatusIsCheked", 
                        function(event, userIsLogged) {
    appName.config(['$routeProvider', 
        '$httpProvider', '$compileProvider',
        function ($routeProvider, 
         $httpProvider, $compileProvider) {
            if (userIsLogged == true) {
                $routeProvider.
                    when('/resetpassword/:hashValue', {
                        templateUrl: 'partials/home.html',
                        controller: 'ResetPasswordController'
                    }).
                    when('/accountsettings', {
                        templateUrl: 'partials/accountsettings.html',
                        controller: 'AccountSettingsController'
                    }).
                    when('/changepassword', 
                      {
                        templateUrl: 
                        'partials/accountsettingschangepassword.html',
                        controller: 'ChangePasswordController'
                    }).
                    when('/edit', {
                        templateUrl: 'partials/accountsettingsedit.html',
                        controller: 'EditAccountController'
                    }).
                    when('/apikeymanagement', {
                        templateUrl: 'partials/apikeymanagement.html',
                        controller: 'APIKeyManagementController'
                    }).
                    when('/dashboard', {
                        templateUrl: 'partials/dashboard.html',
                        controller: 'DashboardController'
                    }).
                    when('/pipelines', {
                        templateUrl: 'partials/pipelines.html',
                        controller: 'PipeLinesController'
                    }).
                    when('/preferences', {
                        templateUrl: 'partials/preferences.html',
                        controller: 'PreferencesController'
                    }).
                    when('/reports', {
                        templateUrl: 'partials/reports.html',
                        controller: 'ReportsController'
                    }).
                    when('/logout', {
                        templateUrl: 'partials/logout.html',
                        controller: 'LogoutController',
                        resolve: {
                            logout: function (logout, $q) {
                                var deferred = $q.defer();
                                logout()['finally'](
                                    function() {
                                        deferred.resolve();
                                    }
                                );
                                return deferred.promise;
                            }
                        }
                    }).
                    when('/privacy', {
                        templateUrl: 'partials/privacy.html',
                        controller: 'PrivacyController'
                    }).
                    when('/tos', {
                        templateUrl: 'partials/tos.html',
                        controller: 'TosController'
                    }).
                    when('/currentStatus', {
                        templateUrl: 'partials/currentStatus.html',
                        controller: 'CurrentStatusController'
                    }).
                    otherwise({
                        redirectTo: '/dashboard'
                    });

            } else {
                /**
                 * If user is not logged default action is
                 * home.
                 */
                $routeProvider.
                    when('/home', {
                        templateUrl: 'partials/home.html',
                        controller: 'HomeController'
                    }).
                    when('/resetpassword/:hashValue', {
                        templateUrl: 'partials/home.html',
                        controller: 'ResetPasswordController'
                    }).
                    when('/privacy', {
                        templateUrl: 'partials/privacy.html',
                        controller: 'PrivacyController'
                    }).
                    when('/tos', {
                        templateUrl: 'partials/tos.html',
                        controller: 'TosController'
                    }).
                    when('/currentStatus', {
                        templateUrl: 'partials/currentStatus.html',
                        controller: 'CurrentStatusController'
                    }).
                    otherwise({
                        redirectTo: '/home'
                    });

            }
        }]);

        angular.bootstrap(document, ['appName']);
});

angular.element(document).ready(function() {
    var injector = angular.injector(['appName']);
    var settings = injector.get('settings');
    var $http = injector.get('$http');

    var functionFactory = function (userStatus) {
        return function () {
            this.lUserStatus = userStatus;
            return this.lUserStatus;
        }
    };

    /**
     * So here we will check if user is logged or
     * not and after this construct conditional routing
     * into config method (above).
     */
    $http.get(settings.apiUri + settings.loginStatus).
             success(function (data) {
        if(angular.isDefined(data.status) && 
            data.status == "NOT_AUTHENTICATED") {
            appName.service('userIsLogged', functionFactory(false));
            angular.element(document).trigger("userStatusIsCheked", [false]);
        } else if(angular.isDefined(data.status) && data.
                status == "AUTHENTICATED") {
            appName.service('userIsLogged', 
            functionFactory(true));
            angular.element(document).trigger("userStatusIsCheked", [true]);
        }
    });
});


Hope this helps someone with a similar problem.

New site dedicated to web development

My wife and I started to create a website dedicated to the development for the web. We hope that this site will be useful to all interested in the subject design and programming. http://codinghunters.com/