Indian Dollar
Indian Dollar

Reputation: 301

angularjs routes, how to check if template file exists

I am using angularjs in my application, all works well but before loading the template I just want to check that it actually exists on its given path.

Here is my code :

    .when("/:page", angularAMD.route({

        templateUrl: function (rp) { 
                     return 'public/templates/' + rp.page.replace('.html', '') + '.php'; },

        resolve: {
        load: ['$q', '$rootScope', '$location', 
            function ($q, $rootScope, $location) {

                 var path = $location.path();
                 //console.log(path);
                 var parsePath = path.split("/");

                 var controllerName = parsePath[1];
                 controllerName = controllerName.replace('.html', '').replace('_', '');
                 var loadController = "public/js/controllers/" +  
                                       controllerName + "Controller.js";

                 var deferred = $q.defer();
                 require([loadController], function () {
                        $rootScope.$apply(function () {
                        deferred.resolve();
                 });
            });
            return deferred.promise;
            }]
        }

    }))

I want that before doing this return 'public/templates/' + rp.page.replace('.html', '') + '.php'; } it must check if this file exists, otherwise I want to redirect to 404 page.

what now happens is, when I visits some invalid link, I dont get 404 status, instead it loads the main index.html file, and for that reason, it starts running the same code in an infinite loop, at last browser hangs.

Appreciate your help, thanks.

Upvotes: 11

Views: 3868

Answers (4)

Aviad
Aviad

Reputation: 531

In ngRoute, you need to configure the routes in the config block, and inside config block you can't use factories and services,
so you can use a simple trick to check if template exists, and if not return your 404 page.

var checkTplUrl = function(url) {
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return (http.status !== 404) ? url : './404.html';
};


.when("/:page", angularAMD.route({

    templateUrl: function (rp) {
        return checkTplUrl('public/templates/' + rp.page.replace('.html', '') + '.php'); },

    resolve: {
        load: ['$q', '$rootScope', '$location',
            function ($q, $rootScope, $location) {

                var path = $location.path();
                //console.log(path);
                var parsePath = path.split("/");

                var controllerName = parsePath[1];
                controllerName = controllerName.replace('.html', '').replace('_', '');
                var loadController = "public/js/controllers/" +
                        controllerName + "Controller.js";

                var deferred = $q.defer();
                require([loadController], function () {
                    $rootScope.$apply(function () {
                        deferred.resolve();
                    });
                });
                return deferred.promise;
            }]
    }

}))

Working example: https://plnkr.co/edit/1UjlFgT7dazMZOrAhZzY?p=info

Upvotes: 1

Sydwell
Sydwell

Reputation: 5024

Create a service that check if the file exist and returns a promise!

$http.head("template2check").then(function () {
                return true;
            }, function () {
                return false;
            });

In the controller use the service:

<service>.<service method>.then(function (found) {
     if (found) {......
});

Upvotes: 0

Reto
Reto

Reputation: 3141

There are a few things you should just do in any non-trivial angular.js app, probably the best place for them is right where you define your mainmodule, then a config block and then a run block.

Without handling and logging those $routeChange Events (resp. when using ui-router $stateChange Events) you are basically blind and will miss errors and duplicate route changes and other nasty things...

Here the example when using ui-router, if using angular basic routing use the respecitve events of angular router.

angular.module('yourMainModuleName', ['your dependencies'])

.config(['$someProvider', function(someProvider) {
    // do setup all your global providers here
    // e.g. $http, restangular, ui-router, angular-translate....

}   ])

.run(['$rootScope', '$state', '$stateParams', 
function($rootScope, $state, $stateParams ) {

    // put ui-router $state on $rootScope, so we have access to it in all $scopes
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;

        $rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
            // always see what happens in your app!
            console.debug('stateChangeStart from: ' + (fromState && fromState.name) + ' to: ' + toState.name);
            // handle auth here as well, check whether user is allowed to go to this state, abort if not
            ...
        });

         $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
            // see what happens in your app!
            console.debug('stateChangeSuccess from: ' + (fromState && fromState.name) + ' to: ' + toState.name);
         });

        // log stateChangeErrors
        $rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
            console.log('Error on StateChange from: "' + (fromState && fromState.name) + '" to:  "'+ toState.name + '", err:' + error.message + ", code: " + error.status);
            $state.go('home');
         });

}]);

Upvotes: 0

micronyks
micronyks

Reputation: 55443

 (or $scope.$on)
 $rootScope.$on("$routeChangeError", function(event, current, previous, eventObj) {
    //redirect your user to custom 404 page;
  });

Upvotes: 0

Related Questions