How would I have ui-router go to an external link, such as google.com?
Asked Answered
R

5

26

For example:

 $stateProvider
            .state('external', {
                url: 'http://www.google.com',

            })

url assumes that this is an internal state. I want it to be like href or something to that effect.

I have a navigation structure that will build from the ui-routes and I have a need for a link to go to an external link. Not necessarily just google, that's only an example.

Not looking for it in a link or as $state.href('http://www.google.com'). Need it declaratively in the routes config.

Revisal answered 13/5, 2015 at 16:54 Comment(1)
I'm not sure if there's a simpler way - there may be. But have you considered a half-way solution, where you have a key (maybe externalURL) in your $route object, a function that redirects the browser if the key/value is present, and simply bind $on("$routeChangeStart", redirectIfExternal) during either the config or run stage?Auto
B
38

Angular-ui-router doesn't support external URL, you need redirect the user using either $location.url() or $window.open()

I would suggest you to use $window.open('http://www.google.com', '_self') which will open URL on the same page.

Update

You can also customize ui-router by adding parameter external, it can be true/false.

  $stateProvider
  .state('external', {
       url: 'http://www.google.com',
       external: true
  })

Then configure $stateChangeStart in your state & handle redirection part there.

Run Block

myapp.run(function($rootScope, $window) {
  $rootScope.$on('$stateChangeStart',
    function(event, toState, toParams, fromState, fromParams) {
      if (toState.external) {
        event.preventDefault();
        $window.open(toState.url, '_self');
      }
    });
})

Sample Plunkr

Note: Open Plunkr in a new window in order to make it working, because google doesn't get open in iFrame due to some security reason.

Bygone answered 13/5, 2015 at 17:10 Comment(8)
interesting. I was hoping for a external: true config parameter or something.Revisal
angular doesn't want you to leave :PSuborder
Just a joke. Angular doesn't want you to leave, they want you to stay on the webpage so they don't provide a simple config parameter like Shane wanted.Suborder
@Suborder hahaha..You are correct..script of one page can't work on other page :DBygone
Hmm...interesting. Let me try that.Revisal
+1 this is the way to go. You should most probably avoid mixing with the existing property url and rather use something like externalUrl, in order to avoid confusion and preserve functionnality of url (the external flag wouldn't be need anymore of course).Hopfinger
@Hopfinger thanks for suggestion..but you can't define a state without url..As I'm rendering href of anchor using ui-sref..so if url is blank then href will not get created by ui-sref directive..& then $stateChangeStart event will never fire..so I think that using url with external flag is an appropriate way of doing this..Bygone
Intereseting idea @Pankaj Parkar. How would you update this code to retain access to parameters? For example, if I wanted to go to www.example.com?user_id=x where x is an incoming UI-Router parameter.Observance
H
27

You could use the onEnter callback:

 $stateProvider
    .state('external', {
        onEnter: function($window) {
            $window.open('http://www.google.com', '_self');
        }
    });

Edit

Building on pankajparkar's answer, as I said I think you should avoid overriding an existing param name. ui-router put a great deal of effort to distinguish between states and url, so using both url and externalUrl could make sense...

So, I would implement an externalUrl param like so:

myApp.run(function($rootScope, $window) {
    $rootScope.$on(
        '$stateChangeStart',
        function(event, toState, toParams, fromState, fromParams) {
            if (toState.externalUrl) {
                event.preventDefault();
                $window.open(toState.externalUrl, '_self');
            }
        }
    );
});

And use it like so, with or without internal url:

$stateProvider.state('external', {
    // option url for sref
    // url: '/to-google',
    externalUrl: 'http://www.google.com'
});
Hopfinger answered 13/5, 2015 at 17:7 Comment(6)
use $location.url() insteadSuborder
You're right, of course better to use angular's utilities than raw javascript. $location.url doesn't seem to work in this context, so thanks also to @pankajparkar for the rest of the solution.Hopfinger
It doesn't? That's surprising... you just tested that?Suborder
@Suborder $location is for navigation between app states, not designed to sail to the external world.Hopfinger
You also can use $window.location.href oder native JS window.location.href / window.location.replaceShakespeare
@KishorK (and hogan) Yes, pure JS works of course, but our point was to use angular wrappers to follow best practice (the main interest is to allow for easy mocking in testing, but that's another question).Hopfinger
R
11

As mentioned in angular.js link behaviour - disable deep linking for specific URLs you need just to use

<a href="newlink" target="_self">link to external</a>

this will disable angularJS routing on a specific desired link.

Regeneration answered 27/3, 2016 at 10:6 Comment(2)
The OnEnter solution may be the cleanest -- and it prevents the listener on $rootScope from being fired all the time. I don't quite understand how "$window" is available without injecting it -- it just seems to work.Clypeus
@Clypeus I think this is simpler, when I want to exclude some links to be engaged in angular routing, this is my point. for that sort I need to add a function to decide for that link separately But when I use target="_self" it exclude the deep linking for those ones we want. I hope this could helpRegeneration
B
1

I transformed the accepted answer into one that assumes the latest version of AngularJS (currently 1.6), ui-router 1.x, Webpack 2 with Babel transpilation and the ng-annotate plugin for Babel.

.run(($transitions, $window) => {
  'ngInject'
  $transitions.onStart({
    to: (state) => state.external === true && state.url
  }, ($transition) => {
    const to = $transition.to()
    $window.open(to.url, to.target || '_self')
    return false
  })
})

And here's how the state may be configured:

.config(($stateProvider) => {
  'ngInject'
  $stateProvider
    .state({
      name: 'there',
      url:'https://google.com',
      external: true,
      target: '_blank'
    })
})

Usage:

<a ui-sref="there">To Google</a>
Bi answered 5/9, 2017 at 10:24 Comment(0)
F
1

The original answer is deprecated and disabled by default in UI Router, you may wish to explore implementing it using transition hooks

  .state("mystate", {
    externalUrl: 'https://google.com'
  })

then:

myApp.run(['$transitions', '$window', ($transitions, $window) => {
  $transitions.onEnter({}, function (transition) {
    const toState = transition.to();

    if (toState.externalUrl) {
      $window.open(toState.externalUrl, '_self');
      return false;
    }
    return true;
  });
}]
);
Flocky answered 13/8, 2020 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.