вторник, 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.

3 коментара:

  1. Този коментар бе премахнат от администратор на блога.

    ОтговорИзтриване
    Отговори
    1. I have the same situation. but I am getting modular error on this line:angular.bootstrap(document, ['studDashboardapp']);

      I have no idea why i am getting this
      i will share my code block here

      //Define an angular module for our app
      angular.module('studDashboardApp', ['studDashboardApp.controllers']);
      var studDashboardapp = angular.module("studDashboardApp", ['ngRoute','ui.bootstrap']);

      angular.element(document).one("userStatusIsCheked", function(event, userIsLogged) {
      studDashboardapp.config([ '$routeProvider','$locationProvider', function($routeProvider, $locationProvider) {
      if (userIsLogged == true) {
      console.log("userIsLogged----"+userIsLogged);
      $routeProvider.when('/MyCourses', {
      templateUrl : 'templates/dashboard/myCourses.html',
      controller : 'MyCoursesController',
      }).when('/course-library', {
      templateUrl : 'templates/dashboard/courseLibrary.html',
      controller : 'CourseLibraryController',
      }).when('/myGuilds', {
      templateUrl : 'templates/dashboard/myGuilds.html'
      }).when('/myConnections', {
      templateUrl : 'templates/dashboard/myConnections.html'
      }).when('/courseQueue', {
      templateUrl : 'templates/dashboard/courseQ.html',
      controller : 'courseQController',
      }).when('/notifications', {
      templateUrl : 'templates/dashboard/notifications.html',
      controller : 'notificationsController',
      }).
      otherwise({
      redirectTo : '/MyCourses'
      });
      }
      else {
      console.log("not userIsLogged----"+userIsLogged);
      $routeProvider.otherwise({ redirectTo: '/MyCourses'});

      }


      } ]);
      angular.bootstrap(document, ['studDashboardapp']);
      });
      angular.element(document).ready(function() {
      var injector = angular.injector(['studDashboardApp']);
      var $http = injector.get('$http');

      var functionFactory = function (userStatus) {
      return function () {
      this.lUserStatus = userStatus;
      console.log("this.lUserStatus");
      console.log(this.lUserStatus);
      return this.lUserStatus;
      };
      };
      var userID = $('#userID').val();
      /**
      * So here we will check the user role
      * and after this construct conditional routing
      * into config method (above).
      */
      $http({ method : 'POST',url: 'userProfile?userID=' + userID })
      .success(function(data, status, headers, config) {
      console.log("userProfile success");
      console.log(data.roles[0]);
      if(data.roles[0]=="StudRestricted") {

      studDashboardapp.service('userIsLogged', functionFactory(false));
      angular.element(document).trigger("userStatusIsCheked", [false]);
      console.log("Restricted------------");
      } else if(data.roles[0]=="Student") {

      studDashboardapp.service('userIsLogged', functionFactory(true));
      angular.element(document).trigger("userStatusIsCheked", [true]);
      console.log("Student------------");
      }

      })
      .error(function(data, status, headers, config) {
      console.log("error in userProfile");

      });

      });

      Изтриване
    2. Hello maneesha. I just now read your comment because it was marked as spam. If you still do not solve your problem you'd better give me a link to a working jsfiddle. This will make it easier to find the problem.

      Изтриване