From 8fa79066e2cea470086769aa59e7cc9d3aa30d81 Mon Sep 17 00:00:00 2001 From: Vojta Jina Date: Fri, 22 Jul 2011 14:58:53 +0200 Subject: doc($location): $location docs + using $location guide --- .../guide/dev_guide.services.$location.ngdoc | 634 +++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 docs/content/guide/dev_guide.services.$location.ngdoc (limited to 'docs/content/guide') diff --git a/docs/content/guide/dev_guide.services.$location.ngdoc b/docs/content/guide/dev_guide.services.$location.ngdoc new file mode 100644 index 00000000..4e0e8548 --- /dev/null +++ b/docs/content/guide/dev_guide.services.$location.ngdoc @@ -0,0 +1,634 @@ +@workInProgress +@ngdoc overview +@name Developer Guide: Angular Services: Using $location +@description + +# What does it do? + +The `$location` service parses the URL in the browser address bar (based on the {@link +https://developer.mozilla.org/en/window.location window.location}) and makes the URL available to +your application. Changes to the URL in the address bar are reflected into $location service and +changes to $location are reflected into the browser address bar. + +**The $location service:** + +- Exposes the current URL in the browser address bar, so you can + - Watch and observe the URL. + - Change the URL. +- Synchronizes the URL with the browser when the user + - Changes the address bar. + - Clicks the back or forward button (or clicks a History link). + - Clicks on a link. +- Represents the URL object as a set of methods (protocol, host, port, path, search, hash). + + +## Comparing $location to window.location + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
window.location$location service
purposeallow read/write access to the current browser locationsame
APIexposes "raw" object with properties that can be directly modifiedexposes jQuery-style getters and setters
integration with angular application life-cyclenoneknows about all internal life-cycle phases, integrates with $watch, ...
seamless integration with html5 APInoyes (with a fallback for legacy browsers)
aware of docroot/context from which the application is loadedno - window.location.path returns "/docroot/actual/path"yes - $location.path() returns "/actual/path"
+ +## When should I use $location? +Any time your application needs to react to a change in the current URL or if you want to change +the current URL in the browser. + +## What does it not do? +Does not cause a full page reload when the browser URL is changed. To reload the page after +changing the URL, use the lower-level API, `$window.location.href`. + + +# General overview of the API + +The `$location` service can behave differently, depending on the configuration that was provided to +it when it was instantiated. The default configuration is suitable for many applications, for +others customizing the configuration can enable new features. + +Once the `$location` service is instantiated, you can interact with it via jQuery-style getter and +setter methods that allow you to get or change the current URL in the browser. + +## $location service configuration + +To configure the `$location` service, you define the `$config` service which is an object with +configuration properties: + +- **html5Mode**: {boolean}
+ `true` - see Html5 mode
+ `false` - see Hashbang mode
+ default: `false` + +- **hashPrefix**: {string}
+ prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)
+ default: `'!'` + +### Example configuration +
+angular.service('$config', function() {
+  return {
+    html5mode: true,
+    hashPrefix: '!'
+  };
+});
+
+ +## Getter and setter methods + +`$location` service provides getter methods for read-only parts of the URL (absUrl, protocol, host, +port) and getter / setter methods for url, path, search, hash: +
+// get the current path
+$location.path();
+
+// change the path
+$location.path('/newValue')
+
+ +All of the setter methods return the same `$location` object to allow chaining. For example, to +change multiple segments in one go, chain setters like this: +
$location.path('/newValue').search({key: value});
+ +All setter methods take an optional boolean flag parameter, which signifies whether current history +record should be replaced or if a new record should be created (default). To change the current URL +without creating a new browser history record you can call: +
$location.path('/newVal', true);
+ +Note that the setters don't update `window.location` immediately. Instead, `$location` service is +aware of the {@link api/angular.scope scope} life-cycle and coalesces multiple `$location` +mutations into one "commit" to the `window.location` object during the scope `$flush` phase. Since +any of the setters can take the replace flag, it's enough for one setter to use this flag in order +to make the entire "commit" a replace operation rather than addition to the browser history. + +### Setters and character encoding +You can pass special characters to `$location` service and it will encode them according to rules +specified in {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}. When you access the methods: + +- All values that are passed to `$location` setter methods, `path()`, `search()`, `hash()`, are +encoded. +- Getters (calls to methods without parameters) return decoded values for the following methods +`path()`, `search()`, `hash()`. +- When you call the `absUrl()` method, the returned value is a full url with its segments encoded. +- When you call the `url()` method, the returned value is path, search and hash, in the form +`/path?search=a&b=c#hash`. The segments are encoded as well. + + +# Hashbang and Html5 Modes + +`$location` service has two configuration modes which control the format of the URL in the browser +address bar: **Hashbang mode** (the default) and the **Html5 mode** which is based on using the +Html5 {@link http://www.w3.org/TR/html5/history.html History API}. Applications use the same API in +both modes and the `$location` service will work with appropriate URL segments and browser APIs to +facilitate the browser URL change and history management. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hashbang modeHtml5 mode
configurationthe default{ html5Mode: true }
URL formathashbang URLs in all browsersregular URLs in modern browser, hashbang URLs in old browser
<a href=""> link rewritingnoyes
requires server-side configurationnoyes
+ +## Hashbang mode (default mode) + +In this mode, `$location` uses Hashbang URLs in all browsers. + +### Example + +
+angular.service('$config', function() {
+  return {
+    html5Mode: false,
+    hashPrefix: '!'
+  };
+});
+
+// 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() == {}
+$location.search({a: 'b', c: true});
+$location.absUrl() == 'http://host.com/base/index.html#!/foo?a=b&c'
+
+$location.path('/new').search('x=y');
+$location.absUrl() == 'http://host.com/base/index.html#!/new?x=y'
+
+ +### Crawling your app + +To allow indexing of your AJAX application, you have to add special meta tag in the head section of +your document: +
+ +This will cause crawler bot to request links with `_escaped_fragment_` param so that your server +can recognize the crawler and serve a HTML snapshots. For more information about this technique, +see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX Applications +Crawlable}. + +## HTML5 mode + +In HTML5 mode, the `$location` service getters and setters interact with the browser URL address +through the HTML5 history API, which allows for use of regular URL path and search segments, +instead of their hashbang equivalents. If the HTML5 History API is not supported by a browser, the +`$location` service will fall back to using the hashbang URLs automatically. This frees you from +having to worry about whether the browser displaying your app supports the history API or not; the +`$location` service transparently uses the best available option. + +- Opening a regular URL in a legacy browser -> redirects to a hashbang URL +- Opening hashbang URL in a modern browser -> rewrites to a regular URL + +### Example + +
+angular.service('$config', function() {
+  return {
+    html5Mode: true,
+    hashPrefix: '!'
+  };
+});
+
+// in browser with html5 history support:
+// open http://host.com/#!/a -> rewrite to http://host.com/a
+// (replacing the http://host.com/#!/a history record)
+$location.path() == '/a'
+
+$location.path('/foo');
+$location.absUrl() == 'http://host.com/foo'
+
+$location.search() == {}
+$location.search({a: 'b', c: true});
+$location.absUrl() == 'http://host.com/foo?a=b&c'
+
+$location.path('/new').search('x=y');
+$location.url() == 'new?x=y'
+$location.absUrl() == 'http://host.com/new?x=y'
+
+// in browser without html5 history support:
+// open http://host.com/new?x=y -> redirect to http://host.com/#!/new?x=y
+// (again replacing the http://host.com/new?x=y history item)
+$location.path() == '/new'
+$location.search() == {x: 'y'}
+
+$location.path('/foo/bar');
+$location.path() == '/foo/bar'
+$location.url() == '/foo/bar?x=y'
+$location.absUrl() == 'http://host.com/#!/foo/bar?x=y'
+
+ +### Fallback for legacy browsers + +For browsers that support the HTML5 history API, `$location` uses the HTML5 history API to write +path and search. If the history API is not supported by a browser, `$location` supplies a Hasbang +URL. This frees you from having to worry about whether the browser viewing your app supports the +history API or not; the `$location` service makes this transparent to you. + +### Html link rewriting + +When you use the history API mode, you will need different links in different browser, but all you +have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>` + +When a user clicks on this link, + +- In a legacy browser, the URL changes to `/index.html#!/some?foo=bar` +- In a modern browser, the URL changes to `/some?foo=bar` + + +In cases like the following, links are not rewritten; instead, the browser will perform a full page +reload to the original link. + +- Links with an `ng:ext-link` directive
+ Example: `link` +- Links that contain `target="_blank"`
+ Example: `link` +- Absolute links that go to a different domain
+ Example: `link` + +### Server side + +Using this mode requires URL rewriting on server side, basically you have to rewrite all your links +to entry point of your application (e.g. index.html) + +### Crawling your app + +If you want your AJAX application to be indexed by web crawlers, you rill need to add the following +meta tag to the HEAD section of your document: +
+ +This statement causes a crawler to request links with empty `_escaped_fragment_` parameter so that +your server can recognize the crawler and serve it HTML snapshots. For more information about this +technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX +Applications Crawlable}. + +### Relative links + +Be sure to check all relative links, images, scripts etc. You must use an absolute path because the +path is going to be rewritten. You can use `` tag as well. + +Running Angular apps with the History API enabled from document root is strongly encouraged as it +takes care of all relative link issues. **Otherwise you have to specify <base href="" /> !** + +### Sending links among different browsers + +Because of rewriting capability in Html5 mode, your users will be able to open regular url links in +legacy browsers and hashbang links in modern browser: + +- Modern browser will rewrite hashbang URLs to regular URLs. +- Older browsers will redirect regular URLs to hashbang URLs. + +### Example + +Here you can see two `$location` instances, both in **Html5 mode**, but on different browsers, so +that you can see the differences. These `$location` services are connected to a fake browsers. Each +input represents address bar of the browser. + +Note that when you type hashbang url into first browser (or vice versa) it doesn't rewrite / +redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL += on page reload. + +In this examples we use `` + + + + + + +# Caveats + +## Page reload navigation + +The `$location` service allows you to change only the URL; it does not allow you to reload the +page. When you need to change the URL and reload the page or navigate to a different page, please +use a lower level API, {@link api/angular.service.$window $window.location.href}. + +## Using $location outside of the scope life-cycle + +`$location` knows about Angular's {@link api/angular.scope scope} life-cycle. When a URL changes in +the browser it updates the `$location` and calls `$apply` so that all $watchers / $observers are +notified. +When you change the `$location` inside the `$digest` phase everything is ok; `$location` will +propagate this change into browser and will notify all the $watchers / $observers. +When you want to change the `$location` from outside Angular (for example, through a DOM Event or +during testing) - you must call `$apply` to propagate the changes. + +## $location.path() and ! or / prefixes + +A path should always begin with forward slash (`/`); the `$location.path()` setter will add the +forward slash if it is missing. + +Note that the `!` prefix in the hashbang mode is not part of `$location.path()`; it is actually +hashPrefix. + + +# Testing with the $location service + +When using `$location` service during testing, you are outside of the angular's {@link +api/angular.scope scope} life-cycle. This means it's your responsibility to call `scope.$apply()`. + +
+angular.service('$serviceUnderTest', function($location) {
+  // whatever it does...
+};
+
+describe('$serviceUnderTest', function() {
+  var scope, $location, $sut;
+
+  beforeEach(function() {
+    scope = angular.scope();
+    $location = scope.$service('$location');
+    $sut = scope.$service('$serviceUnderTest');
+  });
+
+  it('should...', function() {
+    $location.path('/new/path');
+    scope.$apply();
+
+    // test whatever the service should do...
+
+  });
+});
+
+ + +# Migrating from earlier AngularJS releases + +In earlier releases of Angular, `$location` used `hashPath` or `hashSearch` to process path and +search methods. With this release, the `$location` service processes path and search methods and +then uses the information it obtains to compose hashbang URLs (such as +`http://server.com/#!/path?search=a`), when necessary. + +## Changes to your code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Navigation inside the appChange to
$location.href = value
$location.hash = value
$location.update(value)
$location.updateHash(value)
$location.path(path).search(search)
$location.hashPath = path$location.path(path)
$location.hashSearch = search$location.search(search)
Navigation outside the appUse lower level API
$location.href = value
$location.update(value)
$window.location.href = value
$location[protocol | host | port | path | search]$window.location[protocol | host | port | path | search]
Read accessChange to
$location.hashPath$location.path()
$location.hashSearch$location.search()
$location.href
$location.protocol
$location.host
$location.port
$location.hash
$location.absUrl()
$location.protocol()
$location.host()
$location.port()
$location.path() + $location.search()
$location.path
$location.search
$window.location.path
$window.location.search
+ +## Two-way binding to $location + +The Angular's compiler currently does not support two-way binding for methods (see {@link +https://github.com/angular/angular.js/issues/404 issue}). If you should require two-way binding, +you will need to specify an extra property that has two watchers. For example: +
+
+
+
+
+// js - controller
+this.$watch('locationPath', function(scope, path) {
+  $location.path(path);
+});
+
+this.$watch('$location.path()', function(scope, path) {
+  scope.locationPath = path;
+});
+
+ + +# Related API + +* {@link api/angular.service.$location $location API} + + + -- cgit v1.2.3