1. What does it do?
The $location service analyzes the URL in the browser's address bar (based on window.location), allowing us to use the URL more conveniently in the application. Changing the URL in the address bar will respond to the $location service, and modifying the URL in the $location will respond to the address bar.
$location service:
Expose the URL of the current browser address bar, so we can
1. Pay attention to and observe URLs
2. Change URL
When the user does the following, synchronize the URL with the browser:
1. Change the address bar
2. Click the Back or Forward button (or click a historical link).
3. Click a link
A method that describes a URL object as a series of methods (protocol, host, path, search, hash).
1. Compare $location and window.location
1) Purpose: Both window.location and $location services allow read and write access to the current browser's location.
2) API: window.location exposes an unprocessed object with some properties that can be directly modified; while $location service exposes some jQuery-style getter/setter methods.
3) Integration with angular application declaration cycle: $location knows about all internal declaration cycle stages, and integrates with $watch, etc.; while window.location does not work.
4) Seamlessly combine with HTML5 API: with a fallback for legacy browsers, are there any compatibility methods for lower versions of browsers?); while window.location does not.
5) Know the root directory or context of the document loaded by the application: window.location does not work, and wnidow.location.path will return "/docroot/subpath"; and $location.path() returns the real docroot.
2. When should I use $location?
In an application, any time you need to respond to changes to the current URL, or want to change the URL of the current browser.
3. What does it not do?
When the browser URL changes, the page will not be reloaded. If you need to do this (change the address and implement page reload), use a lower-level API, $window.location.href.
2. General overview of the API (Overall overview of the API)
The $location service can behave differently according to the configuration when it is initialized. The default configuration is suitable for most applications, and other configurations are customized, which can enable some new features.
When the $location service is initialized, we can use it in jQuery style getter and setter methods, allowing us to obtain or change the URl of the current browser.
1. $location service configuration
To configure the $location service, you need to obtain $locationProvider (http://code.angularjs.org/1.0.2/docs/api/ng.$locationProvider) and set the following parameters:
html5Mode(mode): {boolean}, true - see HTML5 mode; false - see Hashbang mode, default: false. (The following chapters will explain various modes)
hashPrefix(prefix):{string}, the prefix used by hashbang (when html5Mode is false, use hashbang mode to suit browsers that do not support HTML5 mode), default: '!'
2. Getter and setter methods
The $location service provides getter methods for read-only URL parts (absUrl, protocol, host, port), and also provides getter and setter methods for url, path, search, and hash.
// get the current path $location.path(); // change the path $location.path('/newValue')All setter methods return the same $location object to implement chained syntax. For example, modify multiple attributes in one sentence, the chained setter method is similar:
$location.path('/newValue').search({key:value});
There is a special replace method that can be used to tell the $location service to use a path instead of creating a new history when synchronized with the browser next time you are synchronized with the browser. The replace method is useful when we want to implement redirection but do not want to invalidate the back button (the back button is back and retrieve the redirection) . If you want to change the current URL without creating a new history, we can do this:
$location.path('/someNewPath').replace();
Note that the setter method will not update window.location immediately. Instead, the $location service will know the scope life cycle and merge multiple $location changes into one, and submit it to the window.location object in the $digest stage of scope. Because the changes in multiple states of $location will be merged into one change, in the browser, the replace() method is called only once, so that the entire commit has only one replacement(), which will not cause the browser to create additional history. Once the browser is updated, the $location service will reset the flag bit through the replace() method, and future changes will create a new history unless replace() is called again.
Setter and character encoding
We can pass special characters into the $location service, and the service will automatically encode them according to the RFC3986 standard. When we access these methods:
3. Hashbang and HTML5 Modes
The $location service has two configuration modes that can control the URL format of the browser's address bar: Hashbang mode (default) and HTML5 mode based on using the HTML5 History API. In both modes, the application uses the same API. The $location service will collaborate with the correct URL snippet and browser API to help us perform browser URL changes and history management.
1. Hashbang mode (default mode)
In this mode, $location uses the Hashbang URL in all browsers. Check out the following code snippet to learn more:
it('should show example', inject( function($locationProvider) { $locationProvider.html5mode = false; $locationProvider.hashPrefix = '!'; }, function($location) { // open http://host.com/base/index.html#!/a $location.absUrl() == 'http://host.com/base/index.html#!/a'; $location.path() == '/a'; $location.path('/foo'); $location.absUrl() == 'http://host.com/base/index.html#!/foo'; $location.search() == {};//When search has nothing, return the empty object $location.search({a: 'b', c: true}); $location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c'; $location.path('/new').search('x=y');//You can change the search by string. Every time you set the search, the previous search will be overwritten. $location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'; }));Crawling your app (allows Google to index our app)
If we want our Ajax application to be indexed, we need to add a special meta tag to the head:
<meta name="fragment" content="!" />
Doing so will allow the crawler robot to request the current link using the _escaped_fragment_ parameter, let our server know the crawler robot, and provide the corresponding HTML snapshot. For more information about this technology, please visit https://developers.google.com/webmasters/ajax-crawling/docs/specification?hl=en-CN
4. HTML5 mode
In the HTML5 mode, the getters and setters of the $location service interact with the browser URL through the HTML5 History API, allowing the use of regular path and search modules to replace the hashbang mode. If some browsers do not support the HTML5 History API, the $location service will automatically return to the mode using the hashbang URL. To allow us to get rid of the concerns that it is unclear whether the browser that shows our application supports the history API, using the $location service is the right and best choice.
Opening a regular URL in an older browser will convert to hashbangURL.
Opening a hashbang URL in a modern browser will be rewritten to a regular URL.
1. Forward compatibility with older browsers
For browsers that support HTML5 history API, $location returns to write path and search. If the browser does not support the history API, $location will be converted to provide a Hashbang URL. This is automatically converted by the $location service.
2. HTML link rewriting
When we use history API mode, we need different links for different browsers, but we only need to provide a regular URL, for example <a href="/some?foo=bar">link</a>
When the user clicks this hyperlink:
In the old browser, the URL will be changed to /index.html#!/some?foo=bar
In modern browsers, the URL will be changed to /some?foo=bar
In the following case, the link will not be rewritten, but will cause the page to be loaded into the corresponding URL:
Hyperlink containing target: <a href="/ext/link?a=b" target="_self">link</a>
Absolute link to different domains: <a href="http://angularjs.org/">link</a>
After setting the base path, use the link starting with "/" to the hyperlinks of different base paths: <a href="/not-my-base/link">link</a>
3. server side
Using this method, requesting URL redirection on the server, we usually need to redirect all our links to our application. (for example, index.html).
4. Crawling your app
Same as before
5. Relative links
Make sure to check all relative links, pictures, scripts, etc. We have to specify base url (<base href="/my-base">) in <head> and use absolute url (starting with /) everywhere. Because the relative URL will be converted into an absolute URL based on the initial path of the document (usually different from the root of the application). (relative urls will be resolved to absolute urls using the initial absolute url of the document, which is often different from the root of the application).
We are very encouraged to run angular applications that allow the History API in document root, because this takes into account relative link issues well.
6. Sending links among different browsers
(This explains that the addresses of the two modes can be adapted to different browsers, automatically converted, and repeated again...)
7. Example
In this example, you can see two $location instances, both of which are html5 mode, but on different browsers, so we can see the differences between the two. These $location services are connected to two fake "browsers". Each input represents the address bar of the browser.
Note that when we enter the hashbang address to the first "browser" (or the second?), it will not rewrite or redirect another Url, and this conversion process will only happen when page reload.
<!DOCTYPE html><html ng-app><head> <base href=""/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>fake-browser</title> <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"> <style type="text/css"> .ng-cloak { display: none; } </style></head><body><div ng-non-bindable> <div id="html5-mode" ng-controller="Html5Cntl"> <h4>Browser with History API</h4> <div ng-address-bar browser="html5"></div><br><br> $location.protocol() = {{$location.protocol()}}<br> $location.host() = {{$location.host()}}<br> $location.port() = {{$location.port()}}<br> $location.path() = {{$location.path()}}<br> $location.search() = {{$location.search()}}<br> $location.hash() = {{$location.hash()}}<br> <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> | <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> | <a href="/other-base/another?search">external</a> </div> <div id="hashbang-mode" ng-controller="HashbangCntl"> <h4>Browser without History API</h4> <div ng-address-bar browser="hashbang"></div><br><br> $location.protocol() = {{$location.protocol()}}<br> $location.host() = {{$location.host()}}<br> $location.port() = {{$location.port()}}<br> $location.path() = {{$location.path()}}<br> $location.search() = {{$location.search()}}<br> $location.hash() = {{$location.hash()}}<br> <a href="http://www.host.com/base/first?a=b">/base/first?a=b</a> | <a href="http://www.host.com/base/sec/ond?flag#hash">sec/ond?flag#hash</a> | <a href="/other-base/another?search">external</a> </div></div><script src="../angular.js" type="text/javascript"></script><script type="text/javascript"> function FakeBrowser(initUrl, baseHref) { this.onUrlChange = function(fn) { this.urlChange = fn; }; this.url = function() { return initUrl; }; this.defer = function(fn, delay) { setTimeout(function() { fn(); }, delay || 0); }; this.baseHref = function() { return baseHref; }; this.notifyWhenOutstandingRequests = angular.noop; } var browsers = { html5: new FakeBrowser('http://www.host.com/base/path?a=b#h', '/base/index.html'), hashbang: new FakeBrowser('http://www.host.com/base/index.html#!/path?a=b#h', '/base/index.html') }; function Html5Cntl($scope, $location) { $scope.$location = $location; } function HashbangCntl($scope, $location) { $scope.$location = $location; } function initEnv(name) { var root = angular.element(document.getElementById(name + '-mode')); angular.bootstrap(root, [ function ($compileProvider, $locationProvider, $provide) { debugger; $locationProvider.html5Mode(true).hashPrefix('!'); $provide.value('$browser', browsers[name]); $provide.value('$document', root); $provide.value('$sniffer', {history:name == 'html5'}); $compileProvider.directive('ngAddressBar', function () { return function (scope, elm, attrs) { var browser = browsers[attrs.browser], input = angular.element('<input type="text">').val(browser.url()), delay; input.bind('keypress keyup keydown', function () { if (!delay) { delay = setTimeout(fireUrlChange, 250); } }); browser.url = function (url) { return input.val(url); }; elm.append('Address: ').append(input); function fireUrlChange() { delay = null; browser.urlChange(input.val()); } }; }); } ]); root.bind('click', function (e) { e.stopPropagation(); }); } initEnv('html5'); initEnv('hashbang');</script></body></html>V. Additional instructions
1. Page reload navigation
The $location service only allows us to change the URl; it does not allow us to reload the page. When we need to change the URL and reload the page or jump to other pages, we need to use the low-level point to get the API, $window.location.href.
2. Using $location outside of the scope life-cycle
$location knows angular's scope life-cycle. When the browser's URL changes, it updates $location and calls $apply, so all $watcher and $observer are notified. When we modify $location in the $digest stage, there will be no problem; $location will propagate this modification to the browser and notify all $watcher and $observer. When we need to change $location outside of angular (e.g. in DOM events or in tests), we have to call $apply to propagate this change.
3. $location.path() and ! or / prefixes
The path can be started directly with "/"; the $location.path()setter will be automatically filled when the value does not start with "/".
Note the "!" prefix, in Hashbang mode, does not belong to a part of $location.path(). It's just hashPrefix.
6. Testing with the $location service
When using the $location service in the test, it is outside the angular scope life-cycle. This means we need to be responsible for calling scope.apply().
describe('serviceUnderTest', function() { beforeEach(module(function($provide) { $provide.factory('serviceUnderTest', function($location){ // whatever it does... }); }); it('should...', inject(function($location, $rootScope, serviceUnderTest) { $location.path('/new/path'); $rootScope.$apply(); // test whatever the service should do... }));});7. Migrating from earlier AngularJS releases
In early angular, $location used hashPath or hashSearch to process path and search methods. In this release, when necessary, the $location service processes the path and search methods, and then uses the obtained information to form a hashbang URL (for example, http://server.com/#!/path?search=a).
8. Two-way binding to $location
angular compiler currently does not support two-way binding of methods (https://github.com/angular/angular.js/issues/404). If we want to implement two-way binding to the $location object (using ngModel directive in input), we need to specify an additional model property (for example: locationPath), and add two $watches to listen for $location updates in both directions, for example:
<input type="text" ng-model="locationPath" />
// js - controller$scope.$watch('locationPath', function(path) { $location.path(path););$scope.$watch('$location.path()', function(path) { scope.locationPath = path;});The above is the information about AngularJs Using $location. We will continue to add relevant information in the future. Thank you for your support for this site!