26

I'm trying to use ui-router in my angular app.

My base url is "/segments" and I use base tag to define it.

<base href="/segments" />

Here is my routing config:

var base = "/segments"

$stateProvider
  .state('list', {
    url: base,
    controller: 'FilterLestCtrl',
    templateUrl: '/segments/partial?partial=list'
  })

  .state('new', {
    url: base + '/new',
    data: {
      mode: 'new'
    },
    controller: 'SegmentFormCtrl',
    templateUrl: '/segments/partial?partial=edit'
  })

  .state('edit', {
    url: base + '/:id/edit',
    data: {
      mode: 'edit'
    },
    controller: 'SegmentFormCtrl',
    templateUrl: '/segments/partial?partial=edit'
  });

$locationProvider.html5Mode(true).hashPrefix('!');

When I click to link tag I can't get out from my app to other resource on my site, i.e. I click to tag

<a class="" href="/widgets">Widgets</a>

and then url changing and nothing happened.

Question: How handle external link to other pages on site with ui-router?

Anton Rodin
  • 991
  • 2
  • 12
  • 19

4 Answers4

55

This might be helpful: angular.js link behaviour - disable deep linking for specific URLs

To summarize, you can tell Angular to ignore a link for routing purposes by adding target="_self" to it. This will allow the browser to handle the link unencumbered by Angular. For example:

<a href="/my-non-angular-link" target="_self">My Non-Angular Link</a>

This approach works for links that you know beforehand should not be handled by Angular.

Community
  • 1
  • 1
Heston Liebowitz
  • 1,625
  • 17
  • 12
  • 1
    Based on the limited testing I have done of this, it does not well if you are using this in conjunction with Turbolinks (specify a link with _self seems to cause a full page reload). – a2f0 Dec 29 '14 at 20:54
7

What's happening is ui-router is triggering an otherwise() response for the URL, because it failed to match the URL to the list of known states.

You see the URL update in the browser, but nothing happens because the error was unhandled in the Javascript code.

You can add a handler for unmatched states like this.

var stateHandler = function($urlRouterProvider)
{
    $urlRouterProvider.otherwise(function($injector, $location)
     {
         window.location = $location.absUrl();
     });
};

YourAngularApp.config(['$urlRouterProvider',stateHandler]);

When ui-router fails to match a state it will call the otherwise() callback. You can then manually force the browser to go to that URL.

EDIT: Warning, this will cause an infinite redirect loop if the URL is an Angular path with a bad route.

Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • In some cases, when I go to that next page then try to go Back, the URL in the location bar changes but the page does not. Happens in Chrome and Safari. Has anyone else seen this? – Erik J Aug 21 '14 at 02:43
  • I've seen that happen consistently. Although I like the general nature of this approach, the back-button needs to work. – Heston Liebowitz Sep 12 '14 at 01:46
  • @HestonLiebowitz are you referring to successful routes or failed routes when going back? – Reactgular Sep 12 '14 at 13:32
  • I see this happen for successful redirects to external pages. In fact, clicking the back button changes the URL bar for all prior pages occurring in the Angular app, but won't redirect to any of them. It kind of seems like a browser bug. – Heston Liebowitz Sep 13 '14 at 17:27
6

On a single element, you can just do:

<a href="some/url" ng-click="$event.stopPropagation()">A link outside of the app</a>
mattwad
  • 1,743
  • 17
  • 13
3

First point is: angular handle all click on a element by default and trying resolve value of href attribute via routing system. Information about it is here Angular docs

Second point is: I used wrong base url. Instead of using /segments I should use /segments/. Slash at end of string has a very significant meaning! Angular skip links which isn't on my base (/segments/).

Other solution described here. But I suggest to use

$rootElement.off('click');

in some controller, not in run function. In my case run function has been called before angular binds click handle.

So good luck to everybody! :)

Community
  • 1
  • 1
Anton Rodin
  • 991
  • 2
  • 12
  • 19