Angular UI-Router Not Resolving with Internet Explorer 9 - angularjs

I have an Angular v1.3 application, which uses Angular ui-router v0.2.13 for all routing. The site works great on all browsers, including IE 10 and IE 11, but not IE 9 (we've decided not to pursue IE8, which I understand isn't supported by v1.3, anyway). Despite my best efforts, IE 9 continually resolves to my $stateProvider's otherwise route (which is set to /*path, a possible culprit, so I disabled that route for testing purposes).
In an attempt to get any other route to resolve, I've tried setting $locationProvider.html5Mode(false), modified the $locationProvider.hashPrefix, changed the <base href="/" /> to various URLs, including <base href="/#!"/>, and I've even included xmlns:ng="http://angularjs.org" in the <html> tag for good measure. No matter what I try, IE 9 continually tries to resolve to my otherwise route, or nothing if that route is disabled. BTW, my home page route URL is set to /.
I've been up to my eyeballs in code with a launch deadline looming, so I'll be the first to admit that I'm potentially overlooking something obvious. Can anyone offer any other tips or tricks to cause ui-router to resolve properly in IE 9?

We use something like the following:
<!DOCTYPE html>
<html lang="fr" xmlns="http://www.w3.org/1999/xhtml" ng-csp xml:lang="fr-CA">
//...
var app = angular.module('YourApp', [...]);
angular.bootstrap(document, ['YourApp'], {strictDi: true})
//...
angular.module('YourApp').config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function ($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
cache: false,
controller: 'HomeController as vm'
})
.state('anon', {
url: '/info',
controller: 'AnonController as vm'
})
//etc...

For me, IE9 routes correctly for hash urls, /#/example, but visiting / would resolve to the otherwise route. I worked around this by using a function for otherwise, and checking the url in it.
$urlRouterProvider.otherwise(function($injector){
var state = $injector.get('$state');
var location = $injector.get('$location');
if (!location.url()) {
// handle HTML5 fallback / IE9 when url has no hash
return state.go('home');
}
state.go('404');
});

Related

Is there a way using angular ui router not show #!/login?

If I call $state.go('login') using Angular ui router, the suburl looks like this.
Is there a way to hide #!/login? It's first time to use angular ui router and I dont know even it's possible.
So I want to see only localhost:3000/
You can create a state without an url in ui-router, by simply not defining the url property when configuring your states.
Like this:
angular.module('app').config(function ($stateProvider) {
$stateProvider.state('login', {
component: 'loginComponent'
});
});
You wont be able to navigate directly to the login url. But you'll still be able to use ui-sref or $state.go('login') to navigate.
If you still want to be able to navigate directly to the login page, you can configure another login state in addition to the above, where you specify the url property.
angular.module('app').config(function ($stateProvider) {
$stateProvider.state('login', {
component: 'loginComponent'
}).state('loginDirect', {
url: '/login',
component: 'loginComponent'
});
});
Try this in your config file:
$locationProvider.hashPrefix('');
For e.g.
angular.module('myPageApp', ['ui.router'])
.config(function ($stateProvider, $locationProvider) {
$stateProvider
.state('app',{
url: '/app',
templateUrl: 'someView.html',
controller: 'appController'
})
...
$locationProvider.hashPrefix('');
});
In above code, you can omit # and ! signs but can't skip the routed state in the URL. You can get the URL as localhost:3000/login or you can set the route on '/' identifier.
If your application does not use HTML5 mode or is being run on browsers that do not support HTML5 mode, and you have not specified your own hash-prefix then client side URLs will now contain a ! prefix.
To make your HTML5 mode ON, try following code.
app.config(['$locationProvider', function($locationProvider) {
$locationProvider.hashPrefix(''); // by default '!'
$locationProvider.html5Mode(true);
}]);
Also in your header section of HTML, add this Base ref type as below:
<head>
...
<base href="/">
</head>
For more information, kindly refer this code application here: https://github.com/TheAjinkya/Angular-UI-Router
Hope its helpful!

Error 404 when serving files in angularjs and node app

I have
<base href="/!#/">
at the top of my index.html file. When I go to URL http://localhost:5000/ everything works fine, it instantly add #!/ so the URL is http://localhost:5000/#!/ and page display as expected.
At the server side I have following code which should allow me to use my files
app.use(express.static(path.join(__dirname, 'public')));
Structure of my files is something like:
bookApp(folder)
server.js
public(folder)
index.html
app.js(ngRoute)
views(folder)
css(folder)
controllers(folder)
and my AngularJS routing is:
(function () {
'use strict';
angular
.module('app', [
'ngRoute'
])
.config(config);
function config ($routeProvider) {
$routeProvider
.when('/', {
controller: 'PostsCtrl',
templateUrl: 'views/posts.html'
})
.when('/register', {
controller: 'registerCtrl',
templateUrl: 'views/register.html'
})
.when('/login', {
controller: 'loginCtrl',
templateUrl: 'views/login.html'
})
.otherwise('/');
}
})();
The very first page (views/posts.html) load as expected but when I click
<li>Sign in</li>
the URL is http://localhost:5000/login not as like I thought http://localhost:5000/!#/login.
and it display:
Cannot GET /login
when I manually change URL to http://localhost:5000/#!/login it works fine.
How to fix this behavior?
The only solution I see is to get rid of <base> tag and in every link manually in href directive add !# before slash.
It looks like you are forgetting the ng-view directive: <div ng-view></div> which is the container for the content that is provided by your routing. Place this above your script if you have everything contained in one file.
You can also try:
<ng-view></ng-view>
<div class="ng-view"></div>
Is there any particular reason you are still using Angular 1? I know this isn't technically answering your question, but I would highly recommend that you start using the latest Angular. You can still keep legacy code but it will make a lot of what you are doing a lot cleaner and clear.

Why Angular UI Router does not load my template?

I am really struggling with Angular since it is very fragile i think and I have a very simple case (probably the simplest case ever) which does not work yet.
Here is my module (so i do inject the library):
angular.module(
'module', ['ui.router']
My index.html:
<html data-ng-app="module">
<head>
... several libraries and my js files including ui-router library js + my app.js where the state definitions are located.
</head>
<body>
<div ui-view></div>
</body>
And why is not my template injected in ui-view?
EDIT: Sorry, i was in a hurry, forgot to add some details.. I have updated the app.js section like this:
.state('default',
{
url: '/',
template: '<h1>default</h1>'
})
.state('x',
{
url: '/x',
template: '<h1>X</h1>'
});
Now default state works as expected. But i call the url "host/x" i get a "Cannot GET /x".. when i call the url like "host/#x", it works.
But i have also this section for html5 mode in my app.js:
$locationProvider.html5Mode({
enabled: true,
requireBase: true
});
I have also this in the head section of my index.html:
<base href="/">
I thought, html5 should already handle the hash(#) part of the url? How can i get rid of that # in URL, so i can call directly "host/x"?
You need to specify the url property and go to this url to see this page. State should be something like:
.state("yourStateName", {
template: "<h1>My Contacts</h1>",
url: "/stateURL"
})
This is working example of url provider form my project:
angular.module("app")
.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
$locationProvider
.html5Mode(true);
$urlRouterProvider.when('/', '/url1');
$urlRouterProvider.when('', '/url2');
$urlRouterProvider.when('/url3', 'url4');
$urlRouterProvider.otherwise('/url5');
});

$stateProvider angular add '/#' to my routes

I'm using $stateProvider to handle my routes in Angular 1 and I'm confused as to why my routes have an /# before they all start. I wouldn't mind but when I test those routes in Postman the routes return a 404 error. I'd like to find out why /# that gets added for my routes and get rid of it so I can connect my front end to my backend in node. I'm kind of new to using angular with node this so I'm not sure if I'm explaining my problem correctly.
Here's my code
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/main");
$stateProvider
.state("main", { url: "/main", templateUrl: "templates/main/main.view.html", controller: "MainCtrl" })
.state("map", { url: "/map", templateUrl: "templates/map/map.view.html", controller: "MapCtrl" })
});
These are what my routes look like
http://localhost:8080/#/main
http://localhost:8080/#/map
but I want them to look like
http://localhost:8080/main
http://localhost:8080/map
To get rid of #/ you would have to set $locationProvider.html5Mode(true); in one of your config files.
angular.module('app', []).config(function ($locationProvider) {
$locationProvider.html5Mode(true);
});
For more information on html5 mode vs hashbang mode, have a look at the official angular documentation
Keep one thing in mind though, in html5 mode, your app might not be able to handle page refreshes properly without some server side url re-routing. More information in one of the stack overflow posts here: Reloading the page gives wrong GET request with AngularJS HTML5 mode
Man, just follow advises here and it's gonna be alright. Removing the fragment identifier from AngularJS urls (# symbol).
And one more usefull link https://docs.angularjs.org/guide/$location.

$location / switching between html5 and hashbang mode / link rewriting

I was under the impression that Angular would rewrite URLs that appear in href attributes of anchor tags within tempaltes, such that they would work whether in html5 mode or hashbang mode. The documentation for the location service seems to say that HTML Link Rewriting takes care of the hashbang situation. I would thus expect that when not in HTML5 mode, hashes would be inserted, and in HTML5 mode, they would not.
However, it seems that no rewriting is taking place. The following example does not allow me to just change the mode. All links in the application would need to be rewritten by hand (or derived from a variable at runtime. Am I required to manually rewrite all URLs depending on the mode?
I don't see any client-side url rewriting going on in Angular 1.0.6, 1.1.4 or 1.1.3. It seems that all href values need to be prepended with #/ for hashbang mode and / for html5 mode.
Is there some configuration necessary to cause rewriting? Am I misreading the docs? Doing something else silly?
Here's a small example:
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.3/angular.js"></script>
</head>
<body>
<div ng-view></div>
<script>
angular.module('sample', [])
.config(
['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
//commenting out this line (switching to hashbang mode) breaks the app
//-- unless # is added to the templates
$locationProvider.html5Mode(true);
$routeProvider.when('/', {
template: 'this is home. go to <a href="/about"/>about</a>'
});
$routeProvider.when('/about', {
template: 'this is about. go to <a href="/"/>home</a'
});
}
])
.run();
</script>
</body>
Addendum: in re-reading my question, I see that I used the term "rewriting" without an abundance of clarity as to who and when I wanted to do the rewriting. The question is about how to get Angular to rewrite the URLs when it renders paths and how to get it to interpret paths in the JS code uniformly across the two modes. It is not about how to cause a web server to do HTML5-compatible rewriting of requests.
The documentation is not very clear about AngularJS routing. It talks about Hashbang and HTML5 mode. In fact, AngularJS routing operates in three modes:
Hashbang Mode
HTML5 Mode
Hashbang in HTML5 Mode
For each mode there is a a respective LocationUrl class (LocationHashbangUrl, LocationUrl and LocationHashbangInHTML5Url).
In order to simulate URL rewriting you must actually set html5mode to true and decorate the $sniffer class as follows:
$provide.decorator('$sniffer', function($delegate) {
$delegate.history = false;
return $delegate;
});
I will now explain this in more detail:
Hashbang Mode
Configuration:
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(false)
.hashPrefix('!');
This is the case when you need to use URLs with hashes in your HTML files such as in
link
In the Browser you must use the following Link: http://www.example.com/base/index.html#!/base/path
As you can see in pure Hashbang mode all links in the HTML files must begin with the base such as "index.html#!".
HTML5 Mode
Configuration:
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(true);
You should set the base in HTML-file
<html>
<head>
<base href="/">
</head>
</html>
In this mode you can use links without the # in HTML files
link
Link in Browser:
http://www.example.com/base/path
Hashbang in HTML5 Mode
This mode is activated when we actually use HTML5 mode but in an incompatible browser. We can simulate this mode in a compatible browser by decorating the $sniffer service and setting history to false.
Configuration:
$provide.decorator('$sniffer', function($delegate) {
$delegate.history = false;
return $delegate;
});
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(true)
.hashPrefix('!');
Set the base in HTML-file:
<html>
<head>
<base href="/">
</head>
</html>
In this case the links can also be written without the hash in the HTML file
link
Link in Browser:
http://www.example.com/index.html#!/base/path
Fur future readers, if you are using Angular 1.6, you also need to change the hashPrefix:
appModule.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('');
}]);
Don't forget to set the base in your HTML <head>:
<head>
<base href="/">
...
</head>
More info about the changelog here.
This took me a while to figure out so this is how I got it working - Angular WebAPI ASP Routing without the # for SEO
add to Index.html - base href="/">
Add $locationProvider.html5Mode(true); to app.config
I needed a certain controller (which was in the home controller) to be ignored for uploading images so I added that rule to RouteConfig
routes.MapRoute(
name: "Default2",
url: "Home/{*.}",
defaults: new { controller = "Home", action = "SaveImage" }
);
In Global.asax add the following - making sure to ignore api and image upload paths let them function as normal otherwise reroute everything else.
private const string ROOT_DOCUMENT = "/Index.html";
protected void Application_BeginRequest(Object sender, EventArgs e)
{
var path = Request.Url.AbsolutePath;
var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
var isImageUpload = path.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);
if (isApi || isImageUpload)
return;
string url = Request.Url.LocalPath;
if (!System.IO.File.Exists(Context.Server.MapPath(url)))
Context.RewritePath(ROOT_DOCUMENT);
}
Make sure to use $location.url('/XXX') and not window.location ... to redirect
Reference the CSS files with absolute path
and not
<link href="app/content/bootstrapwc.css" rel="stylesheet" />
Final note - doing it this way gave me full control and I did not need to do anything to the web config.
Hope this helps as this took me a while to figure out.
I wanted to be able to access my application with the HTML5 mode and a fixed token and then switch to the hashbang method (to keep the token so the user can refresh his page).
URL for accessing my app:
http://myapp.com/amazing_url?token=super_token
Then when the user loads the page:
http://myapp.com/amazing_url?token=super_token#/amazing_url
Then when the user navigates:
http://myapp.com/amazing_url?token=super_token#/another_url
With this I keep the token in the URL and keep the state when the user is browsing. I lost a bit of visibility of the URL, but there is no perfect way of doing it.
So don't enable the HTML5 mode and then add this controller:
.config ($stateProvider)->
$stateProvider.state('home-loading', {
url: '/',
controller: 'homeController'
})
.controller 'homeController', ($state, $location)->
if window.location.pathname != '/'
$location.url(window.location.pathname+window.location.search).replace()
else
$state.go('home', {}, { location: 'replace' })

Resources