Angular Hash versus Hashbang - angularjs

Why does Angular sometimes use a hash in the URL and other times use a hashbang? I've started writing two Angular apps from scratch. Neither are using HTML5 mode. Both have the same default route. However, the default URLs display differently.
I've been seeing this random behaviour for at least a year... long before angular-route v1.6. Also, I've always used angular-ui-router.
The default route:
configRoutes.$inject = ['$urlRouterProvider'];
function configRoutes ($urlRouterProvider) {
$urlRouterProvider.otherwise('/');
}
App #1 resolves this...
http://localhost:3000
... to this ...
http://localhost:3000/#/
App #2 resolves this...
http://localhost:3001
... to this ...
http://localhost:3001/#!/
Note the last two characters in the default URL.
I know how to activate HTML5 mode and pretty URLs. That is not what I'm asking. I would really like to understand the significance of both URLs above and why Angular is writing them differently.
Current versions:
angular-ui-router v0.3.2
angular v1.6.0

When we upgraded from angular 1.5 to angular 1.6, the URL of our app changed from /#/ to /#!/. We fixed the problem by configuring the hashPrefix in the application config:
angular.module("myApp").config(function($locationProvider) {
$locationProvider.hashPrefix("");
});

Related

AngularJS html5mode conflicting with third party library

I have a situation with my Angular 1.8.x routing.
In my angularApp.js file, I have html5mode enabled like:
$locationProvider.html5Mode(true);
My NodeJS app does the following:
module.exports = function(express, app){
var router = express.Router();
router.get('/*', function(req, res){
res.render('index.html');
});
app.use('/', router);
};
I do, however, have an issue with a third party library - Snipcart. What that is supposed to do is include E-commerce features to a frontend app. However, Snipcart's "checkout" button links to a URL with # in it and the Snipcart library doesn't work (doesn't go to the checkout and seems to do a few loops of the current page I am on).
My question is simply this - how can I workaround this? html5mode is a must unfortunately but I need to also be able to support links with a # in it.
Thanks in advance!
I don't know if this can be classed as an answer but I spoke to Snipcart and couldn't get it to work. I guess Angular 1 is just indeed that old
You can also consider urls without the hashtag in your project
http://joeljoseph.net/angularjs-remove-hash-from-url/

angular otherwise not working with spring boot

I am facing some weird type of behavior with spring boot + angular js while doing routing. Although routing is working but otherwise redirect to is not working.
For example:
if the url is http://localhost/admin/home#/analysis(working)
if the url is http://localhost/admin/home#/ (working)
but if the url is http://localhost/admin/home (not working)
I have configured otherwise but its not doing any benefit
Below is my code:
.config(['$routeProvider','$httpProvider',function ($routeProvider, $httpProvider) {
$routeProvider.when('/analysis', {
templateUrl : '../resources/views/includes/dashboard.html',
controller : "RegistrationController"
}).when('/', {
templateUrl : '../resources/views/includes/profile.html',
controller : "RegistrationController"
})
.otherwise({
redirectTo: '/'
});
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
I have placed in html
I would suggest you to take a look at $locationProvider.html5Mode(true).
It tells angularJS to use HTML5 strategy if available. Basically # is required for those browsers who do not support HTML5.
Also, you will be required to configure <base> tag of html.
Even when you will implement these concepts, you will stumble across another issue which I faced as well. If you navigate via href in the application, it would work , but if you copy the url and paste it directly in the browser, you'll get error as it would directly hit the server and will try to find necessary URL mapping on the server.
For more details, you can look at this this question which I asked for this issue
I hope it'll help.
Your problem is more related to SEO-related AngularJS implementation, basically, the solution to this is using the rewrite functionality of Apache or Nginx.
For more information, you can start here.

AngularJS and PhoneGap: $location.path causes subsequent tempateUrl lookup to fail

I'm having trouble getting path lookup to work with a AngularJS v1.2.0 and PhoneGap/Cordova Android application. I've come pretty far with html5mode(true) by setting <base href="."/> in index.html and then changing $routeProvider.when('/') to $routeProvider.when('/android_asset/www/index.html'). After that I am able to get redirectTo('login') to reach $routeProvider.when('/login') and there render templateUrl: 'static/partials/login.html' as expected.
The problem I have is that if I instead try to redirect to the login page from my Javascript code with $location.path('/login');, the route is found but templateUrl loading fails with an insecurl exception.
I've tried whitelisting access to file:// by using the new angular-sanitize module, but that does not help.
How can I make $location.path() do the same things as redirectTo so that the partial is loaded? Or is there some other way to solve this problem?
UPDATE: I got a bit forward by adding a call to replace() after the path function, e.g.:
$location.path('/login').replace();
but that seems like a hack, and it still causes the templateUrl in the otherwise route to fail with the same exception.
Any ideas on what might be wrong? Is it that html5mode(true) just does not work at this moment with Phonegap and the only way to fix this is to set it to false and add hashtags to every path (like is done in the angular phonegap seed project)?
For future reference, this is how I managed to solve the problem:
AngularJS currently does not seem to support html5mode(true) inside a Cordova application because of the insecurl problem I reported. What I had to do is add
var h5m = (typeof html5Mode !== 'undefined') ? html5Mode : true;
$locationProvider.html5Mode(h5m);
which gives me the possibility to explicitly set html5Mode in the PhoneGap index.html with a global variable:
<script>
var html5Mode = false;
</script>
So now $location.path('/login') as well as redirectTo: 'login' works, but links in html files, don't. To get those working in PhoneGap, with html5Mode disabled, I had to add #/ in front of every link, e.g. login.
That makes PhoneGap work, but breaks the web page which uses History API with html5Mode(true). The last piece of the puzzle was to add <base href="/"/> to the web page's index.html (and leave it out of the index.html of the PhoneGap project.) So now even though I have a link that says #/login in the web page, I get to the url http://example.com/login and don't see any hashes in the address bar.
**
So in the end I have History API working in my web page and History API disabled in the PhoneGap project (where there really is no need for History API as there is no address bar). The only downside is the extra #/ I have to put in each template html file, but that is a minor annoyance compared to the ability to use all of the same html and javascript files for both web and mobile.
I had this same problem as well. I managed to fix it by skipping the leading slash in the route config:
$routeProvider
// route for the foo page
.when('/foo', {
templateUrl: 'foo.html', //previously: '/foo.html'
controller: 'fooController'
}) //etc.

AngularJS: how to enable $locationProvider.html5Mode with deeplinking

When enabling the html5Mode in AngularJS via $locationProvider.html5Mode(true), navigation seems to be skewed when you land on a page deeper in the site.
for example:
http://www.site.com
when i navigate to the root, i can click all links in the site, Angular's $routeProvider will take over navigating through the site and loading the correct views.
http://www.site.com/news/archive
but when i navigate to this url (or hit refresh when I'm on a deeplink like the above one...) this navigation is not working as I expect it to.
first of all, our as the Documentation for $locationProvider.html5Mode specifies, we catch all urls on the server, similar to the otherwise route in angular, and return the same html as the root domain. But if I then check the $location object from within the run function of angular, it tells me that http://www.site.com is my host and that /archive is my path. the $routeProvider arrives in the .otherwise() clause, since i only have /news/archive as a valid route. and the app does weird stuff.
Maybe the rewriting on the server needs to be done differently, or I need to specify stuff in angular, but currently i'm clueless as to why angular see's the path without the /news segment included.
example main.js:
// Create an application module
var App = angular.module('App', []);
App.config(['$routeProvider', '$locationProvider', function AppConfig($routeProvider, $locationProvider) {
$routeProvider
.when(
'/', {
redirectTo: '/home'
})
.when('/home', {
templateUrl: 'templates/home.html'
})
.when('/login', {
templateUrl: 'templates/login.html'
})
.when('/news', {
templateUrl: 'templates/news.html'
})
.when('/news/archive', {
templateUrl: 'templates/newsarchive.html'
})
// removed other routes ... *snip
.otherwise({
redirectTo: '/home'
}
);
// enable html5Mode for pushstate ('#'-less URLs)
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
}]);
// Initialize the application
App.run(['$location', function AppRun($location) {
debugger; // -->> here i debug the $location object to see what angular see's as URL
}]);
Edit
as per request, more details on the server side:
the server side is organised by the routing of zend framework, and it handles it's own routes (for serving data to the frontend on specific /api urls, and at the end, there is a catch-all route if no specific other route is bound, it serves the same html as the root-route.
so it basically serves the homepage html on that deeplinked route.
Update 2
after looking into the problem we noticed this routing works fine as it is, on Angular 1.0.7 stable, but shows the above described behaviour in the Angular 1.1.5 unstable.
I've checked the change-logs but haven't found anything useful so far, I guess we can either submit it as a bug, or unwanted behaviour linked to a certain change they did, or just wait and see if it get's fixed in the later to be released stable version.
Found out that there's no bug there.
Just add:
<base href="/" />
to your <head />.
This was the best solution I found after more time than I care to admit. Basically, add target="_self" to each link that you need to insure a page reload.
http://blog.panjiesw.com/posts/2013/09/angularjs-normal-links-with-html5mode/
This problem was due to the use of AngularJS 1.1.5 (which was unstable, and obviously had some bug or different implementation of the routing than it was in 1.0.7)
turning it back to 1.0.7 solved the problem instantly.
have tried the 1.2.0rc1 version, but have not finished testing as I had to rewrite some of the router functionality since they took it out of the core.
anyway, this problem is fixed when using AngularJS vs 1.0.7.
Configure AngularJS
$location / switching between html5 and hashbang mode / link rewriting
Configure your server:
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#wiki-how-to-configure-your-server-to-work-with-html5mode
My problem solved with these :
1- Add this to your head :
<base href="/" />
2- Use this in app.config
$locationProvider.html5Mode(true);

Backbone routes break on refresh with Yeoman

I am building an app with Backbone and Yeoman. I am having an issue with the routing.
I have the following routes set up:
'test' : testMethod,
'' : index
I have set up pushstate:
Backbone.history.start({pushState: true});
I am using Chrome
If enter myApp.com#test the url changes to myApp.com/test and testMethod() fires correctly.
However if I try goto myApp.com/test directly or refresh after the browser has changed the url from # to / then I get a 404.
I am using the Yeoman built in server to test the pages. Could this be causing the issue?
I am not sure if you are using BBB within Yeoman. If you are, this should not be an issue. If you are not using BBB, this is a known issue. BBB has it's rewrite rules setup correctly to use pushstate, but yeoman's built in server does not seem to adopt this. You could edit your grunt.js file with your own rewrite rules to get pushstate working correctly. Some of the users in the above mentioned link have done this successfully.
When your app goes live, you will either need to serve those urls through your server or edit your rewrite rules to do the same. If the latter, and your application relies on SEO, SEO will suffer greatly.

Resources