@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
purpose allow read/write access to the current browser location same
API exposes "raw" object with properties that can be directly modified exposes jQuery-style getters and setters
integration with angular application life-cycle none knows about all internal life-cycle phases, integrates with $watch, ...
seamless integration with HTML5 API no yes (with a fallback for legacy browsers)
aware of docroot/context from which the application is loaded no - 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, retrieve the {@link api/ng.$locationProvider $locationProvider} and set the parameters as follows: - **html5Mode(mode)**: {boolean}
`true` - see HTML5 mode
`false` - see Hashbang mode
default: `false` - **hashPrefix(prefix)**: {string}
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)
default: `'!'` ### Example configuration
$locationProvider.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});
There is a special `replace` method which can be used to tell the $location service that the next time the $location service is synced with the browser, the last history record should be replaced instead of creating a new one. This is useful when you want to implement redirection, which would otherwise break the back button (navigating back would retrigger the redirection). To change the current URL without creating a new browser history record you can call:
  $location.path('/someNewPath');
  $location.replace();
  // or you can chain these as: $location.path('/someNewPath').replace();
Note that the setters don't update `window.location` immediately. Instead, `$location` service is aware of the {@link api/ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location` mutations into one "commit" to the `window.location` object during the scope `$digest` phase. Since multiple changes to the $location's state will be pushed to the browser as a single change, it's enough to call the `replace()` method just once to make the entire "commit" a replace operation rather than addition to the browser history. Once the browser is updated, the $location service resets the flag set by `replace()` method and future mutations will create new history records, unless `replace()` is called again. ### 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 mode HTML5 mode
configuration the default { html5Mode: true }
URL format hashbang URLs in all browsers regular URLs in modern browser, hashbang URLs in old browser
<a href=""> link rewriting no yes
requires server-side configuration no yes
## Hashbang mode (default mode) In this mode, `$location` uses Hashbang URLs in all browsers. ### Example
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() == {}
    $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
it('should show example', inject(
  function($locationProvider) {
    $locationProvider.html5mode = true;
    $locationProvider.hashPrefix = '!';
  },
  function($location) {
    // 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: `link` 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 that contain `target` element
Example: `link` - Absolute links that go to a different domain
Example: `link` - Links starting with '/' that lead to a different base path when base is defined
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 will need to add the following meta tag to the HEAD section of your document:
This statement causes a crawler to request links with an 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 either specify the url base in the head of your main html file (``) or you must use absolute urls (starting with `/`) everywhere because 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. Running Angular apps with the History API enabled from document root is strongly encouraged as it takes care of all relative link issues. ### 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 ``

Browser with History API



$location.protocol() = {{$location.protocol()}}
$location.host() = {{$location.host()}}
$location.port() = {{$location.port()}}
$location.path() = {{$location.path()}}
$location.search() = {{$location.search()}}
$location.hash() = {{$location.hash()}}
/base/first?a=b | sec/ond?flag#hash | external

Browser without History API



$location.protocol() = {{$location.protocol()}}
$location.host() = {{$location.host()}}
$location.port() = {{$location.port()}}
$location.path() = {{$location.path()}}
$location.search() = {{$location.search()}}
$location.hash() = {{$location.hash()}}
/base/first?a=b | sec/ond?flag#hash | external
# 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/ng.$window $window.location.href}. ## Using $location outside of the scope life-cycle `$location` knows about Angular's {@link api/ng.$rootScope.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/ng.$rootScope.Scope scope} life-cycle. This means it's your responsibility to call `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...

  }));
});
# 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 app Change 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 app Use 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 access Change 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 to the $location object (using {@link api/ng.directive:input.text ngModel} directive on an input field), you will need to specify an extra model property (e.g. `locationPath`) with two watchers which push $location updates in both directions. For example:


// js - controller
$scope.$watch('locationPath', function(path) {
  $location.path(path);
});

$scope.$watch('$location.path()', function(path) {
  scope.locationPath = path;
});
# Related API * {@link api/ng.$location $location API} a id='n564' href='#n564'>564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116