Improve this doc View Source

Using Angular markup like `{{hash}}` in an href attribute will make the link go to the wrong URL if the user clicks it before Angular has a chance to replace the `{{hash}}` markup with its value. Until Angular replaces the markup the link will be broken and will most likely return a 404 error.

The `ngHref` directive solves this problem.

The wrong way to write it:

    <a href="http://www.gravatar.com/avatar/{{hash}}"/>

The correct way to write it:

    <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>

## Directive Info

- This directive executes at priority level 99.

## Usage

- as attribute:

      <A
        ng-href="">
      ...
      </A>

### Arguments

Param | Type | Details
--- | --- | ---
ngHref | template | any string which can contain `{{}}` markup.

## Example

This example shows various combinations of `href`, `ng-href` and `ng-click` attributes in links and their different behaviors:

Edit in Plunker

    <input ng-model="value" /><br />
    <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
    <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
    <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
    <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
    <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
    <a id="link-6" ng-href="{{value}}">link</a> (link, change location)

    it('should execute ng-click but not reload when href without value', function() {
      element(by.id('link-1')).click();
      expect(element(by.model('value')).getAttribute('value')).toEqual('1');
      expect(element(by.id('link-1')).getAttribute('href')).toBe('');
    });

    it('should execute ng-click but not reload when href empty string', function() {
      element(by.id('link-2')).click();
      expect(element(by.model('value')).getAttribute('value')).toEqual('2');
      expect(element(by.id('link-2')).getAttribute('href')).toBe('');
    });

    it('should execute ng-click and change url when ng-href specified', function() {
      expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);

      element(by.id('link-3')).click();

      // At this point, we navigate away from an Angular page, so we need
      // to use browser.driver to get the base webdriver.

      browser.wait(function() {
        return browser.driver.getCurrentUrl().then(function(url) {
          return url.match(/\/123$/);
        });
      }, 1000, 'page should navigate to /123');
    });

    xit('should execute ng-click but not reload when href empty string and name specified', function() {
      element(by.id('link-4')).click();
      expect(element(by.model('value')).getAttribute('value')).toEqual('4');
      expect(element(by.id('link-4')).getAttribute('href')).toBe('');
    });

    it('should execute ng-click but not reload when no href but name specified', function() {
      element(by.id('link-5')).click();
      expect(element(by.model('value')).getAttribute('value')).toEqual('5');
      expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
    });

    it('should only change url when only ng-href', function() {
      element(by.model('value')).clear();
      element(by.model('value')).sendKeys('6');
      expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);

      element(by.id('link-6')).click();

      // At this point, we navigate away from an Angular page, so we need
      // to use browser.driver to get the base webdriver.
      browser.wait(function() {
        return browser.driver.getCurrentUrl().then(function(url) {
          return url.match(/\/6$/);
        });
      }, 1000, 'page should navigate to /6');
    });