1

Context Users can register with a unique URL slug that identifies their page, e.g. 'http://example.com/slug'.

Current State In my Express.js file, I successfully check my database to see if the slug exists on a user, then redirect the user from 'http://example.com/slug' to 'http://example.com/#!/slug' to take advantage of Angular's routing.

With Angular, however, I can't use $http or $location services in my router file (since it's taking place inside module.config...see this Stack Overflow explanation for more details).

Desire Basically what I want to do is route the user to a 'default' view when a valid slug is found, or home if it's not. Any suggestions would be much appreciated.

For reference, my module.config code can be found here (note that the 'default' state I want to use is 'search'):

core.client.routes.js

'use strict';

// Setting up route

    angular.module('core').config(['$stateProvider', '$urlRouterProvider', 
        function($stateProvider, $urlRouterProvider) {

            // Redirect to home when route not found.
            $urlRouterProvider.otherwise('/');

            // Home state routing
            $stateProvider.
            state('home', {
                url: '/',
                templateUrl: 'modules/core/views/home.client.view.html'
            }).
            state('search', {
                url: '/search',
                templateUrl: 'modules/core/views/search.client.view.html'
            });
        }
    ]);

What I would like to do, is something like this...

'use strict';

// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider', '$http', '$location',
    function($stateProvider, $urlRouterProvider, $http, $location) {

        // Get current slug, assign to json.
        var slug = $location.path();
        var data = {
            link: slug
        };

        // Check db for slug
        $http.post('/my/post/route', data).success( function(response) {
            // Found slug in db
        }).error( function(response) {
            // Route to home
            $location.path('/');
        });

        // Home state routing
        $stateProvider.
        state('home', {
            url: '/',
            templateUrl: 'modules/core/views/home.client.view.html'
        }).
        state('search', {
            // Set URL to slug
            url: '/' + slug,
            templateUrl: 'modules/core/views/search.client.view.html'
        });
    }
]);
Community
  • 1
  • 1
aikorei
  • 570
  • 1
  • 7
  • 23

1 Answers1

2

To directly answer your question, what you want to do is use the routes "resolve" to check for the dependency and redirect to the appropriate view:

angular.module('app', ['ui.router','ngMockE2E'])

  .run(function ($httpBackend) {
    $httpBackend.whenGET(/api\/slugs\/.*/).respond(function (method, url) {
      return url.match(/good$/) ? [200,{name: 'john doe'}] : [404,''];
    });
  })

  .config(function ($stateProvider) {
    $stateProvider
      .state(
        'search',
        {
          url: '/search?terms=:slug',
          template: '<h1>Search: {{vm.terms}}</h1>',
          controllerAs: 'vm',
          controller: function ($stateParams) {
            this.terms = $stateParams.slug;
          }
        }
      )
      .state(
        'slug',
        {
          url: '/:slug',
          template: '<h1>Slug: {{vm.user.name}}</h1>',
          controllerAs: 'vm',
          controller: function (user) {
            this.user = user
          },
          resolve: {
            user: function ($q, $http, $stateParams, $state) {
              var defer = $q.defer();
              $http.get('http://somewhere.com/api/slugs/' + $stateParams.slug)
                .success(function (user) {
                  defer.resolve(user);
                })
                .error(function () {
                  defer.reject();
                  $state.go('search', {slug: $stateParams.slug});
                });
              return defer.promise;
            }
          }
        }
      );
  });
<div ng-app="app">
    <script data-require="angular.js@*" data-semver="1.3.6" src="https://code.angularjs.org/1.3.6/angular.js"></script>
    <script data-require="ui-router@*" data-semver="0.2.13" src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>
    <script data-require="angular-mocks@*" data-semver="1.3.5" src="https://code.angularjs.org/1.3.5/angular-mocks.js"></script>
    <a ui-sref="slug({slug: 'good'})">Matched Route</a>
    <a ui-sref="slug({slug: 'bad'})">Redirect Route</a>
    <div ui-view></div>
  </div>

But, there are a few things you may want to revisit in your example:

  1. Is there a need to perform this check client side if you are already validating and redirecting server side via express?
  2. You seem to be overloading the / route a bit, if home fails, it redirects to itself
  3. You are grabbing slug from $location on app init, not when the view is routed to which could be post init, you need to grab it when ever you are routing to the view
  4. You may want to consider using a GET request to fetch/read data for this request rather than using a POST which is intended generally for write operations (but thats a different story)
  • Thanks for the response, Jeff. Your suggestions helped me to conceptualize several things that were problematic that I was doing (is it painfully obvious that I'm new to AngularJS?). I've simplified things greatly and just put my $http request in my controller entirely. I also changed the url the user gets routed to from 'example.com/#!/slug' to 'example.com/#!/search/slug' (since it was overriding all of my other pages, like /#!/signin, etc.). Again, thanks for the help. – aikorei Dec 16 '14 at 18:43
  • This is also a great alternative: http://stackoverflow.com/questions/24727042/angularjs-ui-router-how-to-configure-dynamic-views – Dante Cullari Jan 18 '15 at 15:24