1
votes

I have the below Angular function.

Function :

var App = angular.module('app', ['ui.bootstrap', 'ngRoute', 'ngAnimate']);

App.config(['$routeProvider', function($routeProvider) {

    $routeProvider

        .when('/', {
            templateUrl: 'views/dashboard.html'
        })
        .when('/:pages', {
            templateUrl: function(routeParams) {
                return 'views/' + routeParams.pages + '.html';
            }
        })
        .otherwise({redirectTo: '404.html'})

}]);

I have a sidebar navigation control. And I've created 4 pages.

So when I click on those navigation items the respective pages open up correctly.

And there are some more pages that I haven't created yet. But as per the below function.

When I don't have something that doesn't exists, it must return to 404.html file that exists in the root of the folder.

What's happening is, I don't get a error in the console and the url the in the address bar reflects the last clicked valid page.

Someone let me know where I'm doing the mistake and whether this method of is correct for dynamic routing?

3

3 Answers

2
votes

The otherwise() part catches paths that do not match to any of the specified routes.
In your case, the route matches, but the template is not available at the specified URL.
$routeProvider doesn't know anything about it and can't do much either.

What you can do, is somehow (see below) check if the template is available and if it is not use $location to redirect to an appropriate path (e.g. /error/404).

In order to determine if the page is valid (i.e. its template is available) you could try to access the template (using $http) and catch any errors (indicating there is no template) etc. But I don't like this approach (as relying on a the availability of a template for determining the page's existence/validity isn't a very good practise imo - e.g. it could easily lead to misleading error messages in case of a network or server problem etc).

My favorite approach is to keep a list of "valid"/existing pages and check against it. If the current page should be available, proceed as usual to fetch the template etc. If not, redirect to an error page.

The logic described above could be placed in $routeProvider's resolve property (so it gets executed before the controller is instantiated and the view loaded).

E.g.:

var app = angular.module(...);

// This should be a constant, so it can
// get injected into configuration blocks
app.constant('EXISTING_PAGES', [
  'page1',
  'page2',
  ...
]);

app.config(function configRouteProvider($routeProvider, EXISTING_PAGES) {    
  $routeProvider.
    when('/', {
      templateUrl: 'views/dashboard.html'
    }).
    when('/:page', {
      templateUrl: function getPageTemplateUrl(routeParams) {
        return 'views/' + routeParams.page + '.html';
      },
      resolve: {
        exists: function resolveExists($location, $route) {
          // Because this is executed before the instantiation of the 
          // controller and the view is not fully loaded yet, the parameters
          // should be accessed via `$route.current.params`
          if (EXISTING_PAGES.indexOf($route.current.params.page) === -1) {
            // This is not a valid/existing page, 
            // let's redirect to an appropriate error page
            $location.replace();   // Replace the URL in the history
            $location.path('/error/404');
          }
          return true;
        }
      }
    }).
    // This should be a separate route, so we can redirect to it
    when('/error/404', {
      templateUrl: '404.html'
    }).
    otherwise({
      redirectTo: '/error/404'
    });
});

See, also, this short demo.

0
votes

otherwise will be called when no other definition matches. But your /:pages definition matches always, resulting in otherwise not being called. The otherwise definition does not react to the 404 from the server when trying to load the template.

The easiest solution to create a route definition for each of your pages, not a generic one. e.g. .when('/page1', ...) .when('/page2', ...) and so on

-1
votes

redirectTo updates the $location and therefore you don't have to specify a .html but to specify a routeParameter.

You should better do something like this:

[...]
.when('/error', { templateUrl: '404.html' })
.otherwise({redirectTo: '/error'});