Angular 1.5 skip nav overridden by router - angularjs

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.

Related

angular routeparams empty on api callback

Im trying to get some paramters from the urlcallback coming from an external authentication, in my angular projct using angular-route/$routeProvider
the api redirects to:
http://localhost:8080/dist/?somevar=someval&val2=someotherval#/
Note the params come before #/
I try to read the get values with $routesparams like:"
$scope.$on('$routeChangeSuccess', function() {
// $routeParams should be populated here
console.log($routeParams.somevar);
console.log($routeParams);
});
This returns an emptyresult. however it i change the url to:
http://localhost:8080/dist/#/?somevar=someval&val2=someotherval
it works, with the api I can give a callback url and I set it like:
?callbackUrl=http://localhost:8080/dist/#/
How should I get these parameters from the url whithout changing the callback url?
In this case, the problem is with the Hashbang mode, which has a hashPrefix #. In the configuration phase, you have to enable html5Mode $locationProvider.html5Mode(true);
But this requires URL rewriting on server side and the HTML <base> tag.
Read more here: https://docs.angularjs.org/guide/$location
So the explanation why it does not work for you this way, is when you give the http://localhost:8080/dist/?somevar=someval&val2=someotherval#/ url to angular, it looks for the parameters after the #, and when you populate the $routeParams, it will create the parameters after the #.

How to get URL segment in Angular JS?

I have URL's in project as:
http://blo.c/news
http://blo.c/video
How I can get segments news, video from these URL?
I tried to use $location in Angular JS, but this object has not these segments
You need to use $location.path()
// given url http://blo.c/news
var path = $location.path();
// => "/news"
If you are using HTML5 mode you must ensure $locationProvider.html5Mode(true) is set so $location works properly.
If you are not using HTML5 mode (which is the case here); then you'll need to drop to traditional javascript to get the URL, since you are not using Angular routing in the first place:
// given url http://blo.c/news
var path = window.location.pathname;
// => "/news"
You might choose to inject $window instead of using window directly, this is only a thin wrapper over the native window object but facilitates testing.
Use the $location.path function to get the url. To get what's after the url, use split
$location.path.split(/\{1}/)[1]
const URL = '/seg1/?key=value';
$location.path();// will return URI segment (in above URL it returns /seg1 ).
$location.search(); // getter will fetch URL segment after ? symbol.
//(in above URL it returns {key:value} object ).
Official Doc: https://docs.angularjs.org/guide/$location

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

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

Problems with AngularJS $location.path

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

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