AngularJS : Unable to make application URL case insensitive in angular-ui-router - angularjs

I am using angular-ui-router in my angular application. I want to make URLs in my application case insensitive. I explored in stack overflow and one of the answers here suggested me to use this code in the app config:
$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
//return $location.absUrl(normalized);
});
However it doesn't work for me and my application returns back to the home page(when trying to alter the case in URL) since my default router page setting is (/Home). When the url changes, I want the code to load the corresponding template and invoke its corresponding controller. What am I doing wrong?

I know this is an old question but it might still help someone who is facing a similar issue.
Since you are normalizing the URL to lowercase, make sure the URL in your state configurations is also lower case.
For example, this will not work:
$stateProvider.state('state1', { url: '/STATE1' ...
This will work:
$stateProvider.state('state1', { url: '/state1' ...

Related

Angular 1.5 skip nav overridden by router

I have an Angular 1.5 app that needs to be accessible. I've added a skipnav i.e:
Skip navigation
however this is being overridden by:
$urlRouterProvider
.otherwise(function ($injector, $location) {
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
How can I set the focus on the #content area?
First of all - The documentation states that the arameter is 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.
So you're redirecting to the 404 state and return the location path which return only the current path without any parameters nor the hash.
What you need to do is to set the hash first (in case it's not already presented in the URL or the url contain a different hash):
$location.hash('content');
And then, return the absolute url with all segments:
return $location.absUrl();
There is a chance that you could just return; without returning any path, because just by setting $location.absUrl() will make angular focus the #content element. Not sure about it, but you can try and see if it's working for you.

Dynamic parameters with ui-router

I'm developing a search app with angular using ui-router.
Requirements:
The search form has too many fields and all have to be optional.
Users should share with another users the URL that display the page with the result list. (So I need to use querystring)
So I could have urls like
path/to/url/list?p=123&v=876
path/to/url/list?c=yes&a=true&p=123
path/to/url/list?z=yes&c=yes&a=true&p=123
path/to/url/list?z=yes&v=876&a=true&p=123
And endless combinations. I know that I can use $location.search() to get all params in json format. That is great! but the question is How can I define the url state with ui-router? Define explicitly all params in the url is not an option. I have read many post but I didn't find a concrete answers.
If you're getting parameters from $location you don't need to define them in state explicitly.
I think, the best way is to use 'resolve' property of $stateProvider configuration:
$stateProvider.state('mystate', {
// Some code here
resolve: {
queryData: ['$location', ($location) => {
$location.absUrl(); // Contains your full URI
return true;
}]
}
});
It's kind of initialization. After that, ui-router will cut URI, but you will store needed data. This case also works fine, when user passing URI directly in browser address input.
Also you can try to set $urlRouterProvider with $urlMatcher for this purposes, but it will be more difficult.

AngularJs $location.path with full url

I want to route the user to an url if he clicks ok in a modal. In my controller i receive urls like
var newUrl = http://localhost:3000/#/dashboard
var newUrl = http://localhost:3000/#/users
as variable.
If i then use
$location.path(newUrl);
it does not work. I also tried
$location.url(newUrl);
but my URL gets encoded like this.
http://localhost:3000/#/#%2Fdashboard
Is there a way to get only the path of the url?
Edit
this code is part of a service. A user make some inputs in a form and clicks on another link for example in the menu. Then a popup appears where he is asked to skip his form changes. If he clicks yes i get the requested url. This is from my development environment on the server of course it will be another url. So i can not just use
$location.path("/users")
for example
I ran into this same problem when having Angular preventDefault $locationChangeStart events, force a save, and only redirect upon success. I define the following function in the body of the controller:
var baseLen = $location.absUrl().length - $location.url().length;
function getPath(fullUrl) {
return fullUrl.substring(baseLen);
}
It doesn't seem like a clean solution, but as a work around, it does the job. A RegEx might work better for you, if you don't know that your URLs are pointing to the same site.
You can use $location.absUrl().
See the official documentation: enter link description here
This method is getter only.
Return full url representation with all segments encoded according to rules specified in RFC 3986.
May I offer a different solution:
$scope.$on('$locationChangeStart', function(e) {
if (meetsTheRequirementsToLeave()) {
return;
}
var newPath = $location.path();
e.preventDefault();
checkIfUserWantsToLeave().then(function() {
$location.path(newPath);
});
});
Within this event $location.path() returns the new path.

Angurlarjs: How to represent state in URL and get state back from URL?

I'm working on a search app using AngularJs 1.0.8.
In order to allow bookmarking and sharing links I want to represent the current state of the search in the browser's location bar.
A URL might look like this
http://example.com/#!/search?s="Some query term"&page=2
So the app has to do two things:
update the URL when someone searches
Restore the state when another opens the same URL
What I currently do (maybe this is the wrong approach) is:
Configuring routeProvider to prevent the browsers from reloading on search param changes
...
$routeProvider.when('/search', {
templateUrl: 'app/search/view/List.html',
controller: 'listCtrl',
reloadOnSearch: false
});
...
Getting search results and setting location when someone presses the search button (searchArray holds the search parameters)
...
$location.search(searchArray);
...
Updating the search results accordingly.
...
$scope.search_results=data;
...
In order to restore the state I'm watching $location.search()
...
$scope.$watch(function () { return $location.search() }, function (newVal) {/* evaluate params and fire query */ });
...
My problem is, that location always changes twice. I've managed to overcome this issue by maintaining dirty flag.
As I think this maintaining state in URL is a popular scenario, I think there must be a better approach with Angular.
Could anyone guide me in to the right direction?

AngularJS Paging with $location.path but no ngView reload

My single page application loads a home page and I want to display a series of ideas. Each of the ideas is displayed in an animated flash container, with animations displayed to cycle between the ideas.
Ideas are loaded using $http:
$scope.flash = new FlashInterface scope:$scope,location:$location
$http.get("/competition.json")
.success (data) ->
$scope.flash._init data
However, to benefit from history navigation and UX I wish to update the address bar to display the correct url for each idea using $location:
$location.path "/i/#{idea.code}"
$scope.$apply()
I am calling $apply here because this event comes from outwith the AngularJS context ie Flash. I would like for the current controller/view to remain and for the view to not reload. This is very bad because reloading the view results in the whole flash object being thrown away and the preloader cycle beginning again.
I've tried listening for $routeChangeStart to do a preventDefault:
$scope.$on "$routeChangeStart", (ev,next,current) ->
ev.preventDefault()
$scope.$on "$routeChangeSuccess", (ev,current) ->
ev.preventDefault()
but to no avail. The whole thing would be hunky dory if I could figure out a way of overriding the view reload when I change the $location.path.
I'm still very much feeling my way around AngularJS so I'd be glad of any pointers on how to structure the app to achieve my goal!
Instead of updating the path, just update query param with a page number.
set your route to ignore query param changes:
....
$routeProvider.when('/foo', {..., reloadOnSearch: false})
....
and in your app update $location with:
...
$location.search('page', pageNumber);
...
From this blog post:
by default all location changes go through the routing process, which
updates the angular view.
There’s a simple way to short-circuit this, however. Angular watches
for a location change (whether it’s accomplished through typing in the
location bar, clicking a link or setting the location through
$location.path()). When it senses this change, it broadcasts an
event, $locationChangeSuccess, and begins the routing process. What
we do is capture the event and reset the route to what it was
previously.
function MyCtrl($route, $scope) {
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
$route.current = lastRoute;
});
}
My solution was to use the $routeChangeStart because that gives you the "next" and "last" routes, you can compare them without the need of an extra variable like on $locationChangeSuccess.
The benefit is being able to access the "params" property on both "next" and "last" routes like next.params.yourproperty when you are using the "/property/value" URL style and of course use $location.url or $location.path to change the URL instead of $location.search() that depends on "?property=value" URL style.
In my case I used it not only for that but also to prevent the route to change is the controller did not change:
$scope.$on('$routeChangeStart',function(e,next,last){
if(next.$$route.controller === last.$$route.controller){
e.preventDefault();
$route.current = last.$$route;
//do whatever you want in here!
}
});
Personally I feel like AngularJS should provide a way to control it, right now they assume that whenever you change the browser's location you want to change the route.
You should be loading $location via Dependency Injection and using the following:
$scope.apply(function () {
$location.path("yourPath");
}
Keep in mind that you should not use hashtags(#) while using $location.path. This is for compability for HTML5 mode.
The $locationChangeSuccess event is a bit of a brute force approach, but I found that checking the path allows us to avoid page reloads when the route path template is unchanged, but reloads the page when switching to a different route template:
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function (event) {
if (lastRoute.$$route.originalPath === $route.current.$$route.originalPath) {
$route.current = lastRoute;
}
});
Adding that code to a particular controller makes the reloading more intelligent.
Edit: While this makes it a bit easier, I ultimately didn't like the complexity of the code I was writing to keep friendly looking URL's. In the end, I just switched to a search parameter and angular handles it much better.
I needed to do this but after fussing around trying to get the $locationChange~ events to get it to work I learned that you can actually do this on the route using resolve.
$routeProvider.when(
'/page',
{
templateUrl : 'partial.html',
controller : 'PageCtrl',
resolve : {
load : ['$q', function($q) {
var defer = $q.defer();
if (/*you only changed the idea thingo*/)
//dont reload the view
defer.reject('');
//otherwise, load the view
else
defer.resolve();
return defer.promise;
}]
}
}
);
With AngularJS V1.7.1, $route adds support for the reloadOnUrl configuration option.
If route /foo/:id has reloadOnUrl = false set, then moving from /foo/id1 to /foo/id2 only broadcasts a $routeUpdate event, and does not reload the view and re-instantiate the controller.

Resources