Anyone knows if there is a tool (or a built-in feature) in angular to obtain a route object from an url string?
Example
I set up route navigation like this:
$routeProvider
.when('/users/:id',
{
templateUrl: 'components/users/edit.html',
controller: 'UsersCtrl',
access: {
requiresLogin: true,
roles: ['Admin']
}
});
I do have a string like /users/2 and i want to be able to obtain the route object asociated with that string, the object containing templateUrl, controller and access properties.
I can see all the routes defined in $route.routes, but the routes there are in the format /users/:id, so I would have to resolve the url manually.
The purpose of this is to secure ui-elements (using a directive) based on route navigation (like spring security with authorize tags)
I do have a directive called navigate-to, that directive allows me to use buttons just like an anchor
<button navigate-to="/users/{{user.id}}">Edit</button>
And I want to determine if the current user is allowed to navigate to the target url (without actually navigating to it).
I can protect navigation with the $routeChangeStart event, what I need is to access the route information (to perform security checks) before routing.
SOLVED:
I have found the way (looking at $route source code) to match the url and obtain the route object (manually), not ideal but it works. Here is the function to get the route information:
var getRouteInfo = function(path) {
var matched = false,
matchedRoute = null;
angular.forEach($route.routes, function(route) {
if (!route.regexp) return;
if (!matched && route.regexp.exec(path)) {
matched = true;
matchedRoute = route;
}
});
return matchedRoute;
};
Related
The backend has created user and needs the email to be confirmed and it has sent out an to the address (see below)
Please confirm your account by clicking
after clicking on the link the user goes to the frontend I have the following route setup using ui.router:
.state('confirmemail', {
url'/confirmemail',
templateUrl: 'client/view/confirmEmail.html' })
how do I get this to route to this state using the above link and how do I access the user and code?
thanks
You can use stateParams:
In the email:
Link
In your config:
.state('confirmemail', { url'/confirmemail/:id', ... })
In your controller:
var myId = $stateParams.id;
// Then lookup user with myId
The link the user clicks on should go to yoursite/confirmemail. Simple as that, just have them navigate to the route that matches the url in your state.
As for passing the information, I can think of a couple options. You could pass a querystring, yoursite/confirmemail?userId=123 or whatever, or you could set up your route to pass some sort of id (or whatever the information may be). Either would have basically the same result. Again, you would define this in your email link then capture it when that path is hit.
Example of passing id using angular:
.state('confirmemail', {
url: '/confirmemail/:id',
resolve: {
id: function ($stateParams) {
return $stateParams.id;
}
}
}
and set the link to yoursite/confirmemail/123 where 123 is the user id.
From there you can inject the id into a controller.
I have two kinds of states in my $stateProvider which are authenticated user access url and public access url..
I have some sort of urls in public access , the thing is i need to prevent these url to access of authenticated user and need to change the url with another one.
Example Suppose,
http://localhost:3000/#/pjobadd/1 is public access url,
if authenticated user will access this url i need to change as http://localhost:3000/#/jobadd/1 .
I'm trying to take the solution as bellow
i have attached parameter in state provider like
.state('admin-panel.public.jobadd', {
url: '/pjobadd/:jobID',
templateUrl: 'app/public/jobadd.tmpl.html',
controller: 'PublicJobaddController',
resolve: {
jobAdd: ['Public', '$stateParams', function(Public,$stateParams) {
return Public.jobAdd($stateParams.jobID);
}]
},
data: {
requireChange: 'pjobadd'
}
})
and used that requireChange in app.js as following
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if (!Auth.isAuthenticated()){
var requireChange = toState.data.requireChange;
console.log(requireChange);
switch(requireChange){
case 'pjobadd':
$state.go('admin-panel.default.jobadd');
case 'psearch':
$state.go('admin-panel.default.search');
}
There are issues i need to append the url passed parameters and $state.go() also not redirecting to the mentioned url.
i don't think that it'l be the efficient way.
Can anyone suggest a way to it???
check this url ...
How to pass parameters using ui-sref in ui-router to controller
can you provide your code here?and give me some more clear information about your requirement..
I'm implementing an angular page-wide authentication app.
It is an event machine that uses an interceptor, so if any request results in a 401 response, it pops a login modal. When the login succeeds, it performs the request again (which could as well result in a 403 if the logged user do not have enough privileges to access the requested resource).
So long, things are working as expected except that when the user cancels the login process, the $location.path() still points to the requested resource. I want to revert this to the previous path. So:
What I expected
I expected to be able to get the "callee" URL like so:
.factory('authInterceptor', ...
return {
// Append the authentication headers to every request
request: function(config) {
previousLocation = $location.path(); // <--- HERE
if(Session.exist) {
config.headers.Authorization = Session.token;
}
return config || $q.when(config);
},
I expected this line to give me the "callee" path, but it actually gives me the requested one (angular has changed it before performing the request).
The route provider
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/admin', {
templateUrl: "/admin"
})
.otherwise({ redirectTo: '/' });
}])
This naughty little boy is changing my path prior to the request. I guess I can do something here on resolve, but I don't find this useful, since it will completely break encapsulation, forcing me to resolve each time I call any protected resource, so I can pass the current path to some service in my auth app.
So, how can I get the previous path from the interceptor, or some service within the auth app, without explicitly sending it from the route provider configuration?
Why don't you watch $on route change events and bind your current/previous paths to a $window or global $scope variable?
I haven't read all your code above, but this is how I handle location things within my app:
$scope.$on('$routeChangeSuccess', function(evt, current, previous){
var routeData = {};
//prop: uriSegment
//desc: get all uri segments for current location
routeData.uriSegment = [];
routeData.uriSegment = $location.path().substr(1).split('/');
//prop: urls
//desc: get current & previous urls
routeData.urls = {};
routeData.urls.curr = $location.url().substr(1);
//...previous url
if(previous && previous.originalPath){
//remove matching structure & slashes from url & add params as plain values
var prevUrl = previous.originalPath.substr(1).replace('/:', '/').replace(':', '');
if(previous.pathParams){
angular.forEach(previous.pathParams, function(val, key){
prevUrl = prevUrl.replace(key, val);
});
}
routeData.urls.prev = prevUrl;
}
//bind routeData to scope/window...
$scope.uriSegment = routeData.uriSegment;
$scope.urls = routeData.urls;
});
How does it work:
1. Get current & previous url:
$scope.urls.curr //shows current url
$scope.urls.prev //shows previous url
... if your route is defined like /admin/:userID and you are on that page, the url will contain that specific userID, it won't return the param name. /admin/53 will be /admin/53.
2. Get a specific url segment from current url:
$scope.uriSegment[1]
... for current url like /admin/53 will print 53
There were a lot more things in the above code, but I think that's what you need - to remember the previous url. You can play with route events and build your own.
I see that you inject $routeScope in your factories, so you can add my code in your main controller and update the $routeScope with routeData on every route change and then you can go like this:
...
previousLocation = $rootScope.urls.prev;
...
More about route events here.
I want to show 404 error page, but also I want to save wrong url in location.
If I'll do something like that:
$urlRouterProvider.otherwise('404');
$stateProvider
.state('404', {
url: '/404',
template: error404Template
});
url will change to /404. How I can show error message on wrong urls without changing actual url?
There is solution for this scenario. We'd use 1) one ui-router native feature and 2) one configuration setting. A working example could be observed here.
1) A native feature of ui-router state definitions is:
The url is not needed. State could be defined without its representation in location.
2) A configuration setting is:
otherwise() for invalid routes, which parameter does not have to be a string with default url, but could be a function as well (cite):
path String | Function The url path you want to redirect to or a function rule that returns the url path. The function version is passed two params: $injector and $location
Solution: combination of these two. We would have state without url and custom otherwise:
$stateProvider
.state('404', {
// no url defined
template: '<div>error</div>',
})
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
Check that all in this working example
As of ui-router#0.2.15 you can use $state.go() and send option not to update the location:
$urlRouterProvider.otherwise(function($injector) {
var $state = $injector.get('$state');
$state.go('404', null, {
location: false
});
});
I'm building a new angularJS app, based from the AngularJS SPA Visual studio template (http://visualstudiogallery.msdn.microsoft.com/5af151b2-9ed2-4809-bfe8-27566bfe7d83)
this uses ui-router (https://github.com/angular-ui/ui-router) for its routing.
however, it seems to be case sensitive.
Any idea how I would instruct angular/ui-router to ignore the case of the url parameter?
case sensitivity doesn't matter while in the app, though should a user type a url to enter the application at a specific page, we need to ensure that about is also the same as aBouT
Cheers
You can now configure ui-router to be case insensitive directly. Here is how you can use it:
angular.module('main', ['ui.router']);
angular.module('main').config(['$urlMatcherFactoryProvider', '$stateProvider', '$urlRouterProvider',
function($urlMatcherFactory, $stateProvider, $urlRouter) {
$urlMatcherFactory.caseInsensitive(true);
$urlMatcherFactory.strictMode(false);
$stateProvider.state('foo', {
url: '/foo',
template: '<b>The Foo View</b>'
});
$stateProvider.state('bar', {
url: '/bar',
template: '<b>The Bar View</b>'
});
$stateProvider.state('nomatch', {
url: '/nomatch',
template: '<b>No match found View</b>'
});
$urlRouter.otherwise('/nomatch');
}
]);
In the latest release (0.2.11), this is broken. A fix has been pushed already that can be seen at Github. So, currently, the best solution is to clone ui-router and build the head of master manually. Alternatively, you can just alter the source manually until the next release comes.
UPDATE (11/18/2014):
A release has now been made that incorporates the fix from above so that you no longer have to pull source and build manually. You can view the release on Github or just get the latest build.
Following the link in the comments to the original question, i was able to get the answer I needed.
Before my $stateProvider.state(......) routes I now have this piece of code:
$urlRouterProvider.rule(function ($injector, $location) {
//what this function returns will be set as the $location.url
var path = $location.path(), normalized = path.toLowerCase();
if (path != normalized) {
//instead of returning a new url string, I'll just change the $location.path directly so I don't have to worry about constructing a new url string and so a new state change is not triggered
$location.replace().path(normalized);
}
// because we've returned nothing, no state change occurs
});
Essentially it will toLowerCase() a url that isn't all lowercase already.
Once done, it replaces the url rather than redirects. Then carries on with matching a state.
You shouldn't change how ui-route handles URL matching to accept case insensitive URLs (that will have unexpected problems), but you can attempt to correct URLs for the user automatically when the routes fail.
When ui-route can not match a URL to a route it triggers the otherWise() callback. I'll show you have to redirect using this callback.
The following makes the assumption that all URLs for your app should be in lower case.
var stateHandler = function($urlRouterProvider)
{
$urlRouterProvider.otherwise(function($injector, $location)
{
var url = $location.absUrl();
var redirect = url.toLowerCase();
if(url == redirect)
{
return;
}
$window.location = redirect;
});
};
YourAngularApp.config(['$urlRouterProvider',stateHandler]);
If you need more control, then use a regex to select which URLs need rewriting.
According to official wiki,
https://github.com/angular-ui/ui-router/wiki/URL-Routing
Darren's answer looks right:
app.config(function ($urlRouterProvider) {
// Here's an example of how you might allow case insensitive urls
$urlRouterProvider.rule(function ($injector, $location) {
//what this function returns will be set as the $location.url
var path = $location.path(), normalized = path.toLowerCase();
if (path != normalized) {
//instead of returning a new url string, I'll just change the $location.path directly so I don't have to worry about constructing a new url string and so a new state change is not triggered
$location.replace().path(normalized);
}
// because we've returned nothing, no state change occurs
});}