Problems with AngularJS $location.path - angularjs

I am having fun and games with a troublesome AngularJS route, so lets see if I can explain this as well as I can.
APP.JS:
app = angular.module("index", []);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/booking/damage/:regnumber', {
templateUrl: 'damage',
controller: 'DamageCtrl'
}).
otherwise({
redirectTo: '/'
});
}
]);
app.controller('IndexCtrl', function($scope, $location) {
$scope.regnumber = '';
$scope.progress = function() {
if ($scope.regnumber !== '') {
$location.path('/booking#/damage/' + $scope.regnumber);
} else {
$location.path('/booking#/damage');
}
};
});
My initial page has a path of
http://localhost/windscreens/glass/index#/index
and within this page is a form that via ng-submit="progress() calls the $scope.progress function within my IndexCtrl controller. There is a field in the form of ng-model="regnumber".
So when filling in the input field with lets say "ABC" and clicking on the button, I'd expect the path to become:
http://localhost/windscreens/glass/booking#/damage/ABC
But it becomes
http://localhost/windscreens/glass/index#/booking%23/damage/ABC
Thing is I am still really becoming used to the Angular routing system and haven't quite got it yet. Any advice on this will be appreciated!
Why am I seeing what I am seeing? What have I got wrong here?

The Angular $routeProvider can only change the part of the URL after the hash (#), so when calling $location.path(), you just use a plain URL fragment like you defined in the route for DamageCtrl.
Some explanation
I'm going to simplify a bit here, but hopefully it will help you understand what's going on.
You're making a SPA (single-page app), so the URL you enter in your browser to get into your app doesn't change while you navigate between routes; by default $routingProvider appends #/whatever/route to that base URL. In your case it looks like you have your entry point (ng-app) in a file called /windscreens/glass/index, so all routes will get appended to that.
Because you don't have an /index route defined that we can see, I'm not sure how http://localhost/windscreens/glass/index#/index is working for you. It should send you to http://localhost/windscreens/glass/index#/ because your otherwise route is just /.
Back to the question
If I understand your question correctly, I would make the index file (where ng-app lives) /windscreens/glass/index.html, then you can just enter http://localhost/windscreens/glass/ to get into the app, because the webserver will serve the contents of index.html by default.
At that point, your index page URL would become http://localhost/windscreens/glass/#/, and your /booking/damage/ routes would be http://localhost/windscreens/glass/#/booking/damage/ABC etc. The code to navigate to them would then be
$location.path('/booking/damage');

Angular routing changes the route on the page; it doesn't take you to a new directory or page.
So if index.html contains your Angular app and you have routes for "booking", "reservation", "cancellations", etc. You'll end up with urls that look like:
/glass/index.html#/booking
/glass/index.html#/reservation
/glass/index.html#/cancellations
The route merely appends itself to the index.html.
So, in a sense, your routes are working correctly. The %23 that you see being added is the url encoded # sign.
If you have a second Angular app that is found at /glass/booking and you're trying to forward the user to it, you can use $window.location.hash and $window.location.pathname. For example,
$window.location.hash = "/damage/ABC";
$window.location.pathname = "/windscreens/glass/booking";
should take you to:
/windscreens/glass/booking#/damage/ABC

Related

Adding a controller to my mean.js app seems to automatically fire an api call?

Having trouble tracking this down. I am adding a workflow to user signup in a meanjs app, such that an admin has to invite a user in order for them to be allowed to signup.
For some reason, whenever the invitation form loads, an API call is attempted to /api/users/invitation which I did not (as far as I know) ask for, and it doesn't make sense to have one as there's no data it needs. I assume there's something being auto-wired for me somewhere, but since this 404 causes the page to fail, I need to kill it if I can.
Here's my controller:
(function () {
'use strict';
angular
.module('users.admin')
.controller('InvitationController', InvitationController);
InvitationController.$inject = ['$scope', '$state', '$window', 'Authentication'];
function InvitationController($scope, $state, $window, Authentication) {
var vm = this;
vm.invitation = {};
vm.sendMail = sendMail;
vm.authentication = Authentication;
function sendMail(isValid) {
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.invitationForm');
return false;
}
var invitation = vm.invitation;
// TODO: send to the server
console.log(invitation);
}
}
}());
Here's the stateprovider fragment that's relevant:
.state('admin.user-invite',{
url: '/users/invitation',
templateUrl: 'modules/users/client/views/admin/invite-user.client.view.html',
controller: 'InvitationController',
controllerAs: 'vm',
data: {
pageTitle: 'Invite a User'
}
})
Any idea where else to look? This is my first app using the MEAN.js framework, though I've used angular quite a bit in the past.
OK, took me an embarrassingly long time to realize this, but it turns out the URL matching was the actual problem at hand.
I should have included my full set of client-side routes in the question, as what was happening was that /users/invitation was actually the last route declared. Turns out, /users/:userId was matching against that, and so the router was interpreting invitations as a userId, and the matching route had a resolver function which was in turn trying to call my server-side users api.
Now the part that is still baking my noodle (though it's less important in that my current problem is solved) is why would the route matcher do that, but still render the template that I'd assigned to the /users/invitation route? The fact that it was doing that certainly made the debugging longer, as the matched route has a very different template assigned to it than my intended route.
Can you examine network requests in developer tools. It could be a request to '/users/invitation', but the '/api' part is getting prefixed on the server side code (prefixed to router??).

ui routing without urlRouterProvider.otherwise

Routing doesn't occur if I don't include $urlRouterProvider.otherwise('/'); in the config.
my go app engine setting with gorilla is
r := mux.NewRouter()
r.HandleFunc(/admin, handleAdmin)
and angularjs config is;
angular.module('admin')
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('home', {
url: '/',
templateUrl: '/admin/index.html',
controller: 'AdminController as admin'
});
//$urlRouterProvider.otherwise('/');
})
when I don't call $urlRouterProvider.othwerwise line, and I open http://localhost:8080/admin I expect to see admin/index.html, but I don't. I see it only if I navigate to http://localhost:8080/admin#/ manually.
But if I add $urlRouterProvider.othwerwise option and go to http://localhost:8080/admin it redirects automatically to http://localhost:8080/admin#/
I don't think this is usual way to do it because I may want "otherwise" to route to a custom 404 page. What point do I miss?
By default, Angular adds the hashPrefix in front of urls. So when you navigate to http://localhost:8080/admin , You don't see index.html since you have not yet visited the url as defined in the angular's ui-router. You will have to navigate to http://localhost:8080/admin/#/ to actuall be in the / state of your application.
It is the same reason that your app doesn't work without the .otherwise(), since then it automatically redirects you to the / state later.
For a possible fix:
Inside your .config function:
// This is in your app module config.
$locationProvider.html5Mode(true);
And in your index.html:
// This is in your index.html head.
<base href="/" />
The problem is not with not having a declared otherwise.
The problem lays on your route. You're specifying the url to be '/', that means the state home is accessible only through http://localhost:8080/admin/ and NOT through http://localhost:8080/admin
What the otherwise does is. When you access the url http://localhost:8080/admin the router try to find a state that matches the url, but don't find it. So it redirects to http://localhost:8080/admin/ which matches with your home state.

Create Angular Dynamic Route

I have a route string like the following var global_book_route = /books/:id specified in a variable.
I want to be able to use $route or $location to deep link to this route in a controller, is there a way to do this without re-specifying the url prefix?
This would work: var id=1; $location.path('books/'+id') -> '/books/1'
However, this does not: $location.path(global_book_route).search({id:1}) -> 'books/:id?id=1'
Is there a way I can use the route specified in the string to go to the correct location?
I think you are mixing up the route itself (/books/:id) with the representation of the route in your code.
For example, your global_book_route should be only "/books/".
Then, if you want to load a specific book, you can go the the location global_book_route + book_id as long as the route is declared in your code, like:
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
}
})
On a side node, when dealing with routes in Angular, it's really worth it to look into angular-ui, the ui-router offers a way better system to manage your routes and states.

how can i change the base url on condition in angularJS

I am caught up in a situation here.
I have a switch in my login page and i want to redirect my service for authorization accordingly.
I want to load my services dynamically after checking some conditions, when i launch my application for the first time. But in angular as we have ng-app and we need to inject all the modules in it at the start. My base url is set before the app is launched. Is it possible to change my base url on condition?
On launching the application the base url gets assigned before the launch of first page which is login page. I have a switch in my login page which if true, i need to set the different base url. But since the base url is set and the control doesnt come again to this module, i am not able to change it conditionally.
This is in my service.js
angular.module('sampleService', ['ngResource'])
.factory('sample', function ($resource, $rootScope) {
$rootScope.serviceUrl = "http://......";
...
});
This is in my app.js
var app = angular.module("sampleApp", ["sampleService"]);
This is how I am using $routeProvider
app.config(["$routeProvider", function ($routeProvider, $locationProvider) {
...
}]);
I want to change my service url conditionally as:
if(myflag)
$rootScope.serviceUrl = "url1";
else
$rootScope.serviceUrl = "url2";
I hope this will give some idea of what i want to do and what i am doing.
Thanks in advance.
I suppose you're using ngRoute in your application, right?
Maybe you should look into uiRouter where you control state. And what you're describing could fall into this category.
https://github.com/angular-ui/ui-router
Also read the differences between the two in this Stackoverflow content.
Yes uiRouter is best solution when it comes to dynamic page loading
Here is a simple PDF on how to use ui-sref in your code ,
Simple Example

Hash removed from default routing in AngularJS

I'm writing an angular app where I need to accept an URL with a fragment hash (OAuth 2.0). Making it short it looks like this.
http://example.com/#access_token=918f4d6e90b25b13ef66a
When this URI is loaded, the routing process does not recognize the path and and it correctly redirects the app to the default route. The problem is that in thi way I loose the hash and I can't parse it anymore.
What I want to do is to parse the hash before it gets removed.
Do you have any idea on a possible solution?
Thanks.
P.S. In this app I can't use HTML5 mode. With it enabled it works just fine.
You just need to define an extra route to "catch" and save the access-token, before redirecting to another route.
E.g.:
$routeProvider
...
.when('/access_token=:accessToken', {
template: '',
controller: function ($location, $routeParams, AuthService) {
AuthService.login( // `AuthService` will save the token
$routeParams.accessToken); // The token is available in `$routeParams
// under the key `accessToken`
$location.path('/'); // Redirect to the default route
$location.replace(); // For better UX, remove this route from history
}
})
See, also, this short demo.
Or navigate directly to this URL for a live demo:
http://fiddle.jshell.net/ExpertSystem/N8CgC/show#access_token=12345.

Resources