Reputation: 14398
I've setup my Angular routes to use the slug from the URL to determine what file to load. It looks like this:
$routeProvider.when("/project/:slug", {
controller: "ProjectController",
template: function($routeParams){
return '<div id="project" ng-include="\'/views/' + $routeParams.slug + '.html\'"></div>';
}
});
Works a charm, but there's no fallback here if the file for the ng-include
doesn't exist. I thought about using resolve, but I can't seem to get it checking the file correctly. My attempt looks like this:
$routeProvider.when("/project/:slug", {
controller: "ProjectController",
resolve: {
check: ["$route", "$http", "$location", function($route, $http, $location){
$http.get("/views/" + $route.current.params.slug + ".html").then(function(res){
if (!res.data) $location.path("/");
else return true;
});
});
},
template: function($routeParams){
return '<div id="project" ng-include="\'/views/' + $routeParams.slug + '.html\'"></div>';
}
});
It's probably worth noting that this is part of a single page application on a MEAN stack. I have my Express routing in NodeJS set up like so:
app.get("*", function(req, res){ res.sendFile(__dirname + "/public/index.html"); });
Upvotes: 0
Views: 1339
Reputation: 14398
It turns out the issue was because I was routing all file requests to my index.html in my NodeJS. So when I tried an $http call to check if a .html view exists, it always returned the index.html and therefore true. The solution was as follows in Node:
app.use(express.static(__dirname + "/public", { maxAge: 86400000 }));
app.get("/framework/*",function(req,res){ res.sendFile(__dirname + "/public" + req.path); });
app.get("/views/*",function(req,res){ res.sendFile(__dirname + "/public" + req.path); });
app.get("*", function(req, res){ res.sendFile(__dirname + "/public/index.html"); });
Then I can use resolve in my Angular routing like so:
$routeProvider.when("/projects/:slug", {
controller: "ProjectController",
resolve: {
check: ["$route", "$http", "$location", function($route, $http, $location){
return $http.get("/views/" + $route.current.params.slug + ".html").success(function(res){
return true;
}).error(function(res){
return $location.path("/");
});
}]
},
template: function($routeParams){
return '<div id="project" ng-include="\'/views/' + $routeParams.slug + '.html\'"></div>';
}
});
So this issue was specific to a single page application setup.
Upvotes: 1
Reputation: 403
You can return a promise from the resolve function. Your example currently fires the request and then returns undefined
.
I have not tested the following, but it should return a promise. (This promise will fail when either, the request fails or the data
property on the response is falsy.
$routeProvider.when("/project/:slug", {
controller: "ProjectController",
resolve: {
check: ["$route", "$http", "$q", function($route, $http, $q){
return $http.get("/views/" + $route.current.params.slug + ".html")
.then(function(res){
if (!res.data) {
return $q.reject('No data');
}
return $q.resolve('Found');
});
}];
},
template: function($routeParams){
return '<div id="project" ng-include="\'/views/' + $routeParams.slug + '.html\'"></div>';
}
});
For the cases where the promise is rejected. (The request failed or there is no data) You could subscribe to the $routeChangeError
event to handle that case and locate the browser to the /
route.
Upvotes: 0