AngularJS Route breaks on manual refresh - angularjs

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.

Related

$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.

Routing issue b/w angularjs and expressjs

Express.js routing of /question/ask
app.get('/question/ask', function (req, res){
console.log('index.js');
console.log('came to question/:id');
res.render('app');
});
The corresponding angularjs routing is:-
when('/ask', {
templateUrl: 'partials/askQuestion',
controller: 'xController'
}).
whereas it should be:-
when('/question/ask', {
templateUrl: 'partials/askQuestion',
controller: 'xController'
}).
I'm working in $locationProvider.html5Mode(true); mode.
Is there anyway i can get the later angularjs routing working. I'm using angularjs 1.1.5 version.
Edit:-
app.get('/*', function (req, res){
console.log('index.js');
console.log('came to question/:id');
res.render('app');
});
has the same problem, the angular route only routes the last /ask for /question/ask.
The issue for me is that I can only do 1 of the following :-
www.example.com/question/:qId
www.example.com/discussion/:aId
because the application will catch only 1 when('/:id', { as it does not include the previous /question/ or /discussion/
Well, if you have the same routes on Express and Angular, if the user types the url directly in the browser you will hit the Express route, but if the user is navigating within the application, then he will hit the Angular route.
Is this what you want ?
What some do is to have a different set of routes on the server for the REST API, and a catch all route to serve the application no matter what the user type as a URL, bringing the user to the home page when a server route is hit. Within the application of course navigation is handled by Angular routes. The problem is that you get no deep linking.
Some other apps have the same routes on both the server and the client, this way they can serve some contents no matter what.
Some will write involved route rewriting to make sure that you both get the application bootstrapping code AND the required URL, thus allowing deep linking.
Cheers
using angular version 1.2.0-rc.3 cures the problem.
change:
var myApp = angular.module('myApp', []);
to
var myApp = angular.module('myApp', ['ngRoute']);
And include:-
script(type='text/javascript', src='js/angular-route.js')

Redirect from Angular JS not working for URL with hash '#'

Background of how I am initializing my AngularJS app is here :
SCRIPT5022: 10 $digest() iterations reached. Aborting! and redirecting to index.html
Summery Problem
When I do a window.location = $scope.myReturnUrl and if the return URL contains a "#", instead of reloading the page, AngularJS captures the url change and it goes to .otherwise part of rout provider setting, and Angular App is loaded again. But, I am expecting it to redirect to specified URL.
Brief of how I am doing this:
I am loading my AngularJS app inside a Bootstrap Modal, this is how I initialize
var markup = '<div id="ng-app" ng-app="myapp" xmlns:ng="http://angularjs.org"><div ng-controller="MyAppAppCtrl"><div ng-view></div></div></div>';
jQuery('#works-modal').html(markup);
angular.bootstrap(jQuery('#ng-app'), ['myapp']);
jQuery('#works-modal').modal('show');
in my app.js, html5mode is set to false for all modules :
$locationProvider.html5Mode(false)
So, when my app is initialized, the url look something like :
http://my-site.uk/user/dashboard.html#/mywork/find/id/9780273651
Now, there is a cancel button on Modal dialog, click on which I am trapping through ng-click, and when clicked, it simply do a redirection something like
window.location = $rootScope.returnToUrl;
now, in my case, return url contains id of the link that was clicked, so that browser can scroll to particular section, the return url is :
http://my-site.uk/user/dashboard.html#my-work1
my rout provider config
$routeProvider.
when('/mywork/find/:id', {
templateUrl: '/mywork/partials/find/find.html',
controller: WorkCtrl
}).
when('/mywork/find/review/submit/:id', {
templateUrl: '/mywork/partials/review.html',
controller: ReviewCtrl
}).
otherwise({
redirectTo: '/mywork/find/id/'+id
});
Problem
Now, when I am trying to redirect to : http://my-site.uk/user/dashboard.html#my-work1
instead of reloading page and scrolling to designated #ID, AngularJS is capturing the URL change and reloading the app instead. this happens because, AngularJS captures the url change and it goes to .otherwise part of rout provider setting, and Angular App is loaded again. But, I am expecting it to redirect to specified URL.
I am use html5mode(true) due to historic reason (mentioned in this thread : SCRIPT5022: 10 $digest() iterations reached. Aborting! and redirecting to index.html)
I don't want to remove the # from my return url because it will break the workflow. Any suggestion how to overcome this?
Thanks,
Ravish
So it sounds like you want http://my-site.uk/user/dashboard.html#my-work1 to redirect you to dashboard.html and scroll to the element with id="my-work1".
You might want to take a look at the $anchorScroll(http://docs.angularjs.org/api/ng.$anchorScroll) service. I'm not sure how it works exactly as I've never needed to use it, but I know it solves problems such as yours.
in your URL (http://my-site.uk/user/dashboard.html#my-work1) try pass 'my-work1'as a parameter in routeProvider like http://my-site.uk/user/dashboard.html/my-work1.
example:
when('/my/route/:param', {
templateUrl: '/mywork/partials/param.html',
controller: WorkCtrl
})
in your controller, get this parameter with $routeParams.
var myParam = $routeParams.param
$location.hash(myParam)//set anchor
$anchorScroll()//do scroll
I hope this solve your problem

Telling Angular Js to ignore a specific route

I have set up my routing in Angular and all works fine:
$locationProvider.html5Mode(true);
$routeProvider.
when('/', { templateUrl: '/Home/Index' }).
when('/User', { templateUrl: '/User/Index' });
However I now have an anchor tag to work as a logout button which will just redirect the user to /User/Logout, and logout will then log the user out and redirect them to the login page. So what I want is for angular js to just ignore this specific route and allow it to do a normal http redirect. This seems like something that should be really easy but I haven't been able to find a solution to the problem.
I know I could do a click event and do a window.location change in the click event but that seems like a really hacky way to do it.
specify target="_self" in your anchors, so that angularjs does not rewrite URLs. See the discussion here: http://docs.angularjs.org/guide/$location
You could use a function with redirectTo also:
.when('/User/Logout', {
redirectTo: function(obj,path,search) {
window.location.href=path;
}
})

Use Angular routing alongside roundtrip routing

I'm working on a Django app which makes heavy use of Angular in some pages, e.g. at domain.com/myAngularApp
Within the angular page I'm using Angular routing for navigating between different views/states within that page. However across the whole website there are navigation links which need to result in round trip requests to Django. However all the pages include the same compiled javascript file which includes the Angular route declarations.
So my question is: how to I get Angular to mange its own routes and get out of the way when the location is changed (primarily by clicking a link on the page) to a path that it hasn't explicitly been told to own, i.e. to different subdirectories off the domain.
My routing declaration looks something like:
myApp.config( function($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/myAngularApp/', {
templateURL: 'template1.html'
});
$routeProvider.when('/myAngularApp/stuff', {
templateURL: 'template12.html'
});
$routeProvider.otherwise({redirectTo: <not sure what to do here...> });
})
I've tried something like:
$routeProvider.otherwise({redirectTo: function(a1,r,a3){ window.location.href = r }})
But this makes the page refresh endlessly on any non-matched route.
Leaving out the otherwise statement seems to make it impossible to leave a page with a non-matched route when accessed directly... don't really understand why?
It must be possible to do what I want no?
I think I may have found a solution. I'm doing a similar thing, a multi-page angular site that uses angular for some of it's pages. Here's what I'm doing
var app = angular.module('appname', ['ui.bootstrap', 'ui.autocomplete'])
.config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
}])
.run(function($rootScope, $location) {
var redirected = false;
$rootScope.$on('$locationChangeStart', function(event, nextLocation, currentLocation) {
if(!redirected && $location.path() !== '/current-url') {
redirected = true;
event.preventDefault();
window.location = $location.path();
}
});
});
So what I have to work out next is how to pass in the current-url path. One way I'm thinking is to us ng-init to set that data in the view (I'm using express.js so I'd use Jade). Or possibly in the run function grab the initial path and test against that.
The event.preventDefault() is there to stop an extra item being added to the browsers history. Before I did that I had to hit back twice to get back to the angular page.
Note This hasn't been tested with IE8 yet. I'm going to do that now and see how it fairs.
Update Ok I just tested this in IE8 and I got stuck in a redirect loop. I've updated the code to have a simple variable to check if we've redirected. Seems to work. I'd love to know a prettier way.

Resources