0

I would like my angular app be aware of a specific query string parameter regardless of which route the user came into the app on. When my app is finished doing whatever is has to do I'd like to present the user with an option to return to their originally intended site.

A typical use case would be to think of someone trying to access a protected URL on one site, being redirected to an identity provider, being identified and then being returned to the site they were originally trying to access.

For example, a user could come to any of the following routes in the app:

https://any.doma.in/#/a?returnTo="https://origin.al/url"
https://any.doma.in/#/b?returnTo="https://origin.al/url"
https://any.doma.in/#/c?returnTo="https://origin.al/url"

I could create a service that would be utilized in every conceivable route defined within my app that would look for the parameter and store it but I don't want to duplicate that code in every defined route.

Is there a way to create a route definition that would always get processed for every route, look for the parameter, and then release the program flow to the original route within my app?

billy
  • 1,435
  • 1
  • 11
  • 11
  • Thanks @BenHarold but hopefully in seeing the answer I just accepted you'll see how my question is different. Is there something I can add to distinguish them more clearly? – billy Jan 13 '16 at 01:53

2 Answers2

1

What you need is a place where you can check for that parameter every time the URL changes. Since the .config method is only called the one time (when the app is ... err.. configured), you could use the .run method instead.

So, let's assume that your query item is called returnTo. I like the way that sounds.

I'm assuming you have a routeProvider config call similar to this:

YourAngularApp.config(['$routeProvider', function ($route) {

.... code for routes here ....


}]);

And, lets assume you have a call to your service that looks like this:

https://any.doma.in/#/a?returnTo=https://origin.al/url

Oops... wait. That won't work. That little "?" comes after your # ... so the browser will actually go back in time. It will literally travel backward 2 seconds and leave you in the same programmer loop forever unless you break the cycle and restore proper order to the universe. Until you do, you'll be stuck in that Aeron like a pear-shaped Sisyphus.

https://any.doma.in/?returnTo=https%3A%2F%2Forigin.al%2Furl%0D%0A#/a

OK. I feel better. Now what? Well ... back to that .config call above. We can just append a .run method call to the bottom of that file:

YourAngularApp.run(['$rootScope','$location', function($rootScope, $location) {

    $rootScope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
        var myParameterValue = getParameterByName('returnTo');
        if(myParameterValue != '') {
            $rootScope.returnTo = myParameterValue;
            //do whatever it is you want to do with that parameter here.
        }
    });

    function getParameterByName(name) {
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
    }

}]);

Note that I'm adding a little getParam method that I yanked from here because

(a) thought the code should be complete in the post and

(b) I assume you don't want to include the parameter as an optional parameter on every one of your angular routes and

(c) I assume you hate jQuery (seems to be alot of that going around in the angular community).

Not sure what you need to do, but I'm guessing you can take a look at settings in $rootScope to figure out what steps to take with returnTo... this will get you that parameter's value in the same codeblock as $rootScope and $location ... You should be able to take it from here!

And - this gets you access without having to remember to code it into every route in your app! Just don't forget that pesky url formatting stuff above. Good luck!

Community
  • 1
  • 1
bri
  • 2,932
  • 16
  • 17
  • I would've accepted this sooner but I had to restore order to the universe ;-) Thank you for what appears to be an excellent solution and exactly what I was trying to think up myself. I've never received an answer with humor, that was quite refreshing! – billy Jan 13 '16 at 01:49
  • I played around a bit and found what turned out to be a much simpler solution although it allows the query to be at the end which seems wrong according to the spec. – billy Jan 21 '16 at 15:21
0

Expecting the following url: https://any.doma.in/#/a?returnTo="https://origin.al/url"

The value can be retrieved on app load like this:

angular
    .module('app.module')
    .run(lookForParameter);

function lookForParameter($rootScope, returnToService, $location) {
    $rootScope.$on('$locationChangeStart', function() {
        var search = $location.search();

        if (search.returnTo && angular.isString(search.returnTo)) {
            returnToService.url = search.returnTo;
        }
    });
}

Thanks @bri for the assistance in getting to this solution.

billy
  • 1,435
  • 1
  • 11
  • 11