I am using ui-router in an angular single page application. I have some routes defined, and I have a specific 404 route like this:
app.config(function($urlRouterProvider, $stateProvider){
$urlProvider.otherwise('404')
$stateProvider
.state('example', {
url: '/example/:id',
templateUrl: 'example.html',
controller: 'ExampleController'
})
.state('404', {
url: '*path',
templateUrl: '404.html'
})
})
Notice how the url for 404 state is '*path', which means it will match any path. I made it so if the user types something like '/some-non-existent-url' he won't be redirected to '/404', but rather stay at '/some-non-existent-url', but see the 404.html template. Here comes the problem: say my app interacts with some REST API inside my ExampleController, and the API may return an object, or it may return 404 Not Found based on the id from the url it receives. So, inside my controller, whenever this happens, I try to redirect to 404:
app.controller('ExampleController', function($state){
someAPICall().then(function(response){ // do something},
function(response){
if(response.status == 404){
$state.go('404');
}
});
});
This is where the weird staff occurs. It displays the 404.html template - for a split second - and then redirects to home page (did not include it in my code here for the sake of brevity). My guess is that the '404' state does not have a real url specified: if I change it's url from '*path' to '/404' for example, this works fine, but I don't want to do this, as the user won't see which was the real url that caused a 404 response. Is there any workaround for this problem?
You have a mistake in your code. You are writing $urlProvider.otherwise('404'). Change it to $urlRouterProvider.otherwise('404').
That should get it working.
What worked for me was to remove $urlProvider.otherwise('404') and have the 404 state as the last state
Related
I am facing a number of troubles related to AngularJs routing. I have already tried to find answers online but I still am not very clear with the solutions provided.
First of all, here is my routing block:
var myApp = angular.module('myApp', ["ngRoute", "ngAnimate"]);
myApp.config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when("/", {
templateUrl: "../view/home.html",
controller: "slideShowController",
})
.when("/business&consumer", {
templateUrl: "../view/govnservices.html",
controller: "productController",
})
.when("/about", {
templateUrl: "../view/about.html",
controller: "pagController",
})
.when("/project", {
templateUrl: "../view/projects.html",
controller: "projController",
})
.when("/service", {
templateUrl: "../view/services.html",
controller: "servController",
})
.otherwise({
redirectTo: '/',
})
});
And this is how I am passing the reference to my links:
Home
Another link:
name: "About Us",
templateUrl: "/about",
Now everywhere it is specified as:
Home
But on using '#' my links are not working (still don't know why.)
Again on not using '#' all my links are working but if I try to reload my page then it gives a 404 error:page not found.
Someone please help me out with this and please mention in comment if any part is not clear. Also please mention any good source to learn routing.
Your question is not entirely clear where you state: "Again on not using '#' all my links are working but if I try to reload my page then it gives a 404 error:page not found."
So are you using the # or not? Since we are talking html5mode I will assume not for now (Because you have to not use it in that mode)...
So I assume the symptom your seeing is that you
Navigate to "http://wheremyappishosted/" This loads your app and
everything is fine...
Now you click "About", This changes your
location to "http://wheremyappishosted/about" and again everything
works just fine.
Now you hit Refresh in your browser and suddenly
you get a 404
Sounds about right? If so... The problem is your server and not the AngularJS routing...
This is what happens from the servers perspective:
A request for "http://wheremyappishosted/" is received, the server responds
with the main page for the app. Everything is fine...
AngularJS handles the route change, the server does not receive any requests
for "http://wheremyappishosted/about" It DOES however receive a request for
the template "../view/about.html" which it can find and responds with.
Everything is fine...
A request for "http://wheremyappishosted/about" is received, but the server
does not know what to respond for that so it gives a 404...
The solution is that you need your to deliver your main page as a fallback route... You may wan't to have certain filters in place so that a unknown route under the parent route "api" may still fail with a 404 etc...
But the essence of it is that the server doesn't know what to respond with for "http://wheremyappishosted/about", so you need to configure it so it knows that.
I trying to make an application that contains multiple views as template. The templates are under the js/app/pages/ folder. And I have 2 templates to show and route. My routing section is:
var app = angular.module("myApp", ['ngRoute', 'ngMaterial']);
app.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/Page', {
templateUrl: 'js/app/pages/Page.html',
controller: 'pageController',
reloadOnSearch: false
})
.when('/Settings', {
templateUrl: 'js/app/pages/Settings.html',
controller: 'settingsController',
reloadOnSearch: false
})
.when('/Admin', {
templateUrl: 'js/app/pages/Admin.html',
controller: 'adminController',
reloadOnSearch: false
})
.otherwise({
redirectTo: '/Page'
});
$locationProvider.html5Mode(true);
});
And my html file contains
<div id="menu"></div>
<div ng-view></div>
Menu div contains menu elements that route me between the pages. For example, when I run this site on browser, URL will be localhost/Page, and when I click the settings button URL change with localhost/Settings. But when I press the F5 button in my keyboard. Page gives me error The resource cannot be found..
I search on the internet "how to refresh routing page in angularjs" and find some solutions but I couldn't make them work for me. I tried $route.reload() and $routeUpdate() method but that does not work for me. Maybe I'm wrong in something.
If you are using Apache server this should work run this in terminal
sudo a2enmod rewrite && sudo service apache2 restart
works for me
Solved! I couldn't manage refresh with ngRoute. Then i convert it into ui-router. I declare the states by urls. And the refresh is working. Thanks for comments and answers. Maybe this will help someone.
Actually when you are pressing F5 from keyboard, it is hitting to your server for that page, not angular because you don't have any # sign between your URL. For angular, URL should be like as - localhost/#/Page
Use html5mode
A great article about it here
to init its very simple
.config(function($routeProvider, $locationProvider) {
// other routes here
$locationProvider.html5Mode(true);
});
When you "reload a page", you whole app will reinit again. That means if you are not on the main page, and the sub route you are at missing some data, you will likely get an error.
You should look into resolve attribute for routes, so for example,
.when('/Settings', {
templateUrl: 'js/app/pages/Settings.html',
controller: 'settingsController',
reloadOnSearch: false,
resolve: {
resourceone: function(){return whatsneeedtoberesolvehere;}
}
})
that way no matter where your app is reloaded, it will have the necessary data to boot the page
Just keep the # in URL, you don't have to put extra effort to manage reloads etc. you can think a "#" in URL represent a specific state in single page application.
Otherwise it can be managed by module rewriting, that map the url with hashed version URL internally for AngularJs app.
I am using express, angular, and ui-router for my webpage. I would like the url for each user's page to be very simple: www.mysite.com/username
This is similar to Twitter's design. My angular state provider for the user pages looks like this:
$stateProvider
.state('userPage', {
url: '/:username',
templateUrl: 'js/user-page/user-page.html',
controller: 'UserPageCtrl'
});
The only issue is now when I try to navigate to any other page whose state is defined with only one URL part (ie. www.mysite.com/login), the app always parses the URL as a user page (but without being able to find a user).
Is there any way to tell angular to try and load the URL as a defined state before treating the url as a dynamic parameter?
I can simply require all other routes to have two parameters (ie. www.mysite.com/login/userlogin), but that doesn't seem very elegant.
You just need to define the login state first. Order is important.
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'somewhere/login.html',
controller: 'LoginPageCtrl'
},
.state('userPage', {
url: '/:username',
templateUrl: 'js/user-page/user-page.html',
controller: 'UserPageCtrl'
},
});
If a user navigates to /login then a matching state will be searched for. It will check your first state, then the second and so on until a matching state is found. In this case, the login state will match so the searching for another matching state will cease.
I am writing a CRUD app with AngularJS + UI Router.
I want to be able to parse the current location in the browser URL and determine if a ui-router state should be applicable for the current url.
In these sample routes, is there some way to do the if and unless clauses?
(url in browser address bar is http://example.com/notes/1/edit_me)
$stateProvider.state("root", {
url: "",
unless: $location.matches(/\edit_me/)
})
$stateProvider.state("edit", {
url: "/edit",
if: $location.matches(/\edit_me/)
//
})
UPDATE 1
The reason I want to do the above:
Say I am at http://example.com/notes. The routes is
$stateProvider.state("root", {
url: "",
})
However, with the same above ui.route state, when I am at url http://example.com/notes/edit, the root is now "/notes/edit" instead of "/notes"
UPDATE 2
#adam, more explanation of what I am trying to accomplish:
I will try to explain: in your code, for your home state, the (ui.router's) url is / (aka hash syntax #!/)
However, the URL in browser address bar looks like http://example.com/notes/ in one case and http://example.com/notes/edit in another case. (note that the URLs do not contain any #! portion since we have just navigated to the page)
Now the home's / is going to match in both cases of above URL.
But since the second URL ends in notes/edit, I want that the home for this URL should be #!/edit, and not #!/.
Basically I am trying to mix server-side rendered pages (/notes and /notes/edit are rendered by server, not AngularJS)
and client side routing so that no matter which URL we are at, the client can figure out which (ui.router) route applies to the current URL.
Make sense?
Sorry i don't really understand your needs but here's an example of use of ui-router:
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/index.html',
controller: 'MainCtrl'
})
$stateProvider
.state('edit', {
url: '/edit',
templateUrl: 'app/edit/edit.html',
controller: 'EditCtrl'
})
$stateProvider
.state('edit.note', {
url: '/note',
templateUrl: 'app/edit/note.html',
controller: 'NoteCtrl'
});
$urlRouterProvider.otherwise('/');
i'm not sure if a copy paste will work, but try to adapt it with your case. Hope it will help.
Edit:
I'm afraid that i can't help you more than that. The design of your app with rendered page without angular sounds really special.
Have you tried the example i provide you? If yes, hav you simply format the url by addind
" #!/ " where you need it.
For example:
$stateProvider
.state('edit', {
url: '#!/edit', //or something like, url:'/#!/edit'
templateUrl: 'app/edit/edit.html',
controller: 'EditCtrl'
});
Check this link also may be it will help you:https://github.com/angular-ui/ui-router/issues/372
ui-sref may help you
But the place to see usefull example for ui-router it's his own doc.
https://github.com/angular-ui/ui-router
and here:
http://angular-ui.github.io/ui-router/site/#/api/ui.router
I want to show 404 error page, but also I want to save wrong url in location.
If I'll do something like that:
$urlRouterProvider.otherwise('404');
$stateProvider
.state('404', {
url: '/404',
template: error404Template
});
url will change to /404. How I can show error message on wrong urls without changing actual url?
There is solution for this scenario. We'd use 1) one ui-router native feature and 2) one configuration setting. A working example could be observed here.
1) A native feature of ui-router state definitions is:
The url is not needed. State could be defined without its representation in location.
2) A configuration setting is:
otherwise() for invalid routes, which parameter does not have to be a string with default url, but could be a function as well (cite):
path String | Function The url path you want to redirect to or a function rule that returns the url path. The function version is passed two params: $injector and $location
Solution: combination of these two. We would have state without url and custom otherwise:
$stateProvider
.state('404', {
// no url defined
template: '<div>error</div>',
})
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
Check that all in this working example
As of ui-router#0.2.15 you can use $state.go() and send option not to update the location:
$urlRouterProvider.otherwise(function($injector) {
var $state = $injector.get('$state');
$state.go('404', null, {
location: false
});
});