stateProvider using htm5Mode cannot GET error - angularjs

I am using stateProvider with $locationProvider.html5Mode:
// Redirect any unmatched url
$urlRouterProvider.otherwise("/cool");
$stateProvider
// Dashboard
.state('cool', {
url: "/cool",
templateUrl: "views/cool.html"
});
$locationProvider.html5Mode(true);
But when I http://localhost:8080/cool I will get Cannot GET /cool error. http://localhost:8080/ and http://localhost:8080/#/cool is working correctly.
After some research I found out the problem is because of grunt connect. so I added modRoute to route all url to index.html:
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
modRewrite([
'!\\.\\w+$ /'
]),
but now the problem is every url like http://localhost:8080/uncool to http://localhost:8080/cool.

First, make sure you have the "base"-tag in your head.
<base href="/">
Then make sure that your "/cool"-page serves the same thing as your "/". If not, the server will send back 404 (as expected). This has to be true for all your "sub pages".
To test if this is the case – create a link with a href to "/cool", angular should handle this "internally" with a pushState, which differs from just "browsing" to that page. Meaning, when you click the link, the page will serve as expected, but if you reload (CTRL + R), you will get the error.

If you use html5mode you have to include <base> tag in your head part in document. You can set requireBase to false and use html5mode without <base> tag. Please have a look at angular documentation and ui-router documentation

Related

Angular: $locationProvider.html5Mode(true) routing issue

I want to remove the # from my URLs, so I have the code below:
angular.module('building')
.config(['$stateProvider', '$locationProvider',
function ($stateProvider, $locationProvider) {
// Turn on #-less links.
$locationProvider.html5Mode(true);
$stateProvider
.state('building', {
url:'/building',
templateUrl: 'app/modules/building/building.html',
controller: 'BuildingQuery',
controllerAs: 'vm'
})
}]);
And I have <base href="/"> in my index.html file.
And the code works...sort of.
If I enter a link like this...
http://127.0.0.1:4000/#/building
Then the browser redirects that URL to...
http://127.0.0.1:4000/building
and loads the page.
However, if I enter this url...
http://127.0.0.1:4000/building
then...
Cannot GET /building
Because the # URLs redirect properly, I know $locationProvider.html5Mode(true); is doing something.
Any ideas? It might be useful to know that I'm using angm to generate the modules.
From the Angular docs:
Using [html5mode] requires URL rewriting on server side, basically you
have to rewrite all your links to entry point of your application
(e.g. index.html). Requiring a <base> tag is also important for this
case, as it allows Angular to differentiate between the part of the
url that is the application base and the path that should be handled
by the application.
I.e. you need to tell your server to rewrite any requests to /building to /index.html.
evsheino pointed me in the right direction. There's nothing wrong with my code, it was the server configuration causing problems. All I had to do was add the following to my gruntfile.js
middleware: function (connect, options) {
var optBase = (typeof options.base === 'string') ? [options.base] : options.base;
return [require('connect-modrewrite')(['!(\\..+)$ / [L]'])].concat(
optBase.map(function(path){ return connect.static(path); }));
},
keepalive: true,
port: 4000,
base: '.',
hostname: 'localhost',
debug: true,
livereload: true,
open: true
}
}
},
Full explanation can be found here: http://jjt.io/2013/11/16/angular-html5mode-using-yeoman-generator-angular/
EDIT: this was for connect

Refreshing AngularJS stateProvider states

I'm using StateProvider for routing in my website. Changing states from one to the other work, but whenever I refresh the page on any view, I get a 404 not found error (The requested URL /about was not found on this server.). For example, I have localhost/about (I set html5Mode to be true and require base to be false) but when I refresh it, it doesn't show that view anymore.
I am using this in my index.html page
<base href="/">
and this in my config file
state('about', {
url: '/about',
templateUrl: 'templates/about.html',
controller: 'AboutController',
}).
What is the cause of this and how can I resolve the refreshing issue?

How can I get AngularJS ui-router to respond correctly to a browser page refresh?

I have created an AngularJS application that uses ur-router. Here's a small sample of the config:
$locationProvider.html5Mode(true);
var admin = {
name: 'admin',
url: '/Admin',
views: {
'root': {
templateUrl: '/app/admin/partials/home.html',
},
'content': {
templateUrl: '/app/admin/partials/overview.html',
}
}
};
var adminContent = {
name: 'admin.content',
parent: 'admin',
url: '/:content',
views: {
'root': {
templateUrl: '/app/admin/partials/home.html',
},
'content': {
templateUrl: function (stateParams) {
return '/app/admin/partials/' + stateParams.content + '.html';
},
}
}
};
Everything is working when I start up the application, then go to the /Admin with a link and next I go to the reference link and it brings up the page:
http://xx.com/Admin/reference
When I click the browser back button it goes back to the previous page as expected.
However if I do a refresh now everything goes wrong. It forgets about ui-router and tries to find the page: xx.com/Admin/Reference
For reference I am using: #version v0.2.13
My index file looks like this:
<head>
<base href="/" />
Can someone give me some suggestions as to what I am doing wrong?
This is happening because you are using HTML5mode. You can either disable it or configure your server to handle it.
When you click a link on the page, the javascript changes the displayed url, but it does not actually navigate to the new url. When you refresh, the browser makes a request to the server for the new url. The server is treating it as a regular request, but it does not have any page at that url, so it returns a 404. You can configure the server to redirect any url to your main page so that this doesn't happen. When you refresh (with proper configuration), the server will send back index.html (or whatever your main page is) and the javascript can fetch the arguments out of the url.
This doc explains how to configure the server in ui-router. https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
You will also need a <base> tag so that angular can tell the difference between the url arguments and the rest of the url.
Example <base> tag:
If your site is http://www.example.com/ and you are on the Admin page (http://www.example.com/Admin), your base tag would look like <base href="http://www.example.com/">
For more info on the different routing modes in Angular see: https://docs.angularjs.org/guide/$location

UI-Router: why is there a leading "/" on my child state's url?

I am using AngularJS along with ui-router. My project root is at / while my angular app is at /panel/.
I have 5 states: login, logout, main (an abstract state), main.home, and main.holiday.
Everything seems fine at first, I could access main.home, login, logout. However, when I access main.holiday, I noticed that there is a leading slash /panel//holiday.
Here's a gist to each state (I thought that putting every snippet here would be a bad idea).
My SPA HTML:
<!-- ... -->
<head>
<base href="/panel/">
</head>
<!-- ..-->
I think this is some sort of bug, no? By the way, here's a link to the plnkr where I seem to have reproduced the problem.
Copied from my Reddit response (although I seem to not be the first to chime in):
// This can have an empty URL unless it needs to add something useful
// For example, it could be '/www' but '/' is pointless and the cause of your issue
var main = {
name: 'main',
abstract: true,
url: '',
template: '<div ui-view></div>'
};
Also:
// Add a '/' URL to this state since it's not abstract.
// Else changing from another state to this one won't impact the URL, which is weird
var home = {
name: 'main.home',
url: '/',
template: 'You are in main.home'
};
I solved this problem with both methods:
by simple removing the url property of the main abstract state. Or,
Setting the url property of the main abstract state to a blank string (url: '').

AngularJS Route breaks on manual refresh

In the config method, I have some routes defined as follows:
$locationProvider.html5Mode(true);
$routeProvider.when('/', {
...
});
$routeProvider.when('/front', {
...
});
$routeProvider.when('/user/account', {
...
});
Everything works fine when navigating through the app using <a href=""> tags. However, when I go to /user/account and manually refresh my browser, it pops the /account off the route and redirects me to /user, breaking the rendering in the process since there is no route defined for /user.
I noticed this does not happen when I configure the route to be /account only, but this is not fixing the real issue. So I set up the following catch-all (below the routes above) to log what's happening:
$routeProvider.otherwise({
redirectTo: function() {
console.log('bumped', arguments);
return '/';
}
});
and saw it was trying to match /account instead of /user/account. What is going on here?
I am on Angular 1.1.5. The server returns index.html appropriately on all requests (for HTML5 mode), so it seems like a client-side issue.
How can I configure this route correctly?
EDIT
Turns out this is a bug in 1.1.5 core.
https://github.com/angular/angular.js/issues/2799
patched here
https://github.com/IgorMinar/angular.js/commit/2bc62ce98f893377bfd76ae211c8af027bb74c1d
Ended up using ui-router which solved this issue.

Resources