Pass URL to as $routeParam in AngularJS app

前端 未结 4 1808
慢半拍i
慢半拍i 2021-02-01 22:21

How can I pass actual URL (with slashes, commas, etc.) as a $routeParam to AngularJS App?

this will work: http://paprikka.github.io/le-bat/#/preview/asdadasda

4条回答
  •  借酒劲吻你
    2021-02-01 22:46

    Ok, I've managed to find a solution working with current stable version (@1.0.7).

    Current way of handling this problem will involve $route-related events, parsing angular-incompatible urls on the fly and handling them via an additional service working in a similar way as $http interception.

    You can see working code examples here: http://embed.plnkr.co/fIA2xj/preview

    Main steps

    1. pass an angular-incompatible url as usual, eg. go to site.com/url/http://site.com
    2. listen to a $routeChangeStart event and extract correct url parameter for paths beginning with /url/
    3. encode the correct url parameter to an angular-compatible form (in this particular case, I use base64). Don't use encodeURIComponent, because angular will treat as any other url
    4. redirect to another route with your business logic, eg. site.com/parsed-url/BASE64_GOES_HERE
    5. decode the URL in the controller and use it as usual :)

    Code

    Create angular app module as usual

    angular.module('routes',[]).config([
    
      '$routeProvider',
    
      function($routeProvider){
        $routeProvider
          .when('/test', {templateUrl: 'test.html'})
          // This one is important:
          // We define a route that will be used internally and handle 
          // parameters with urls parsed by us via the URLInterceptor service 
          .when('/parsed-url/:url', {templateUrl: 'url.html', controller:'URLCtrl'})
          .when('/', {redirectTo: '/test'})
          .otherwise({templateUrl: '404.html'});
    
      }
    
    ])
    

    URL Interceptor service (singleton)

    .service('URLInterceptor', function($rootScope, $location){
      // We listen to $routeChangeStart event and intercept it if 
      // the path matches our url scheme. In this case, every route
      // beginning with /url/ will be caught
      $rootScope.$on('$routeChangeStart', function(e, next, current){
    
        // $location.path does change BEFORE actual routing happens,
        // so in this case we get parsed new location object
        // for free.
    
        // To be hones, a better way of handling this case might be using 
        // $locationChangeStart event instead, but it would require us to parse urls 
        // manually.
        var path = $location.path();
        // check if string begins with '/url/'
        var matcher = path.slice(0,5);
        var cleanPath = '';
        if (matcher === '/url/'){
          // Yes it does, yay!
          // Remove leading '/url/' to extract the actual parameter
          cleanPath = path.slice(5);
          // Encode our url to a safe version. We know that encodeURIComponent won't 
          // work either, so a good choice might be base64.
          // I'm using https://code.google.com/p/javascriptbase64/downloads
          $location.path('/parsed-url/' + Base64.encode(cleanPath));
          // Prevent default event execution. Note that, it won't cancel related $location Events
          e.preventDefault();
        }
      });
    
      return {
        decode: Base64.decode,
        encode: Base64.encode
      }
    })
    

    Controllers

    // Main application controller
    // We instantiate our URLInterceptor service here
    .controller('AppCtrl',function($scope, $location, URLInterceptor){
      $scope.navigateTo = function (path) {
        $location.path('/url/' + path);
      }
    })
    .controller('URLCtrl', function($scope, $routeParams, URLInterceptor){
      $scope.url = URLInterceptor.decode($routeParams.url);
    });
    

    Two things you should remember:

    1. Although I tried to create a solution as clean as possible, usually passing the data this way to angular isn't considered a good practice, so try not to use it unless you really need to.
    2. You can handle this issue with only one route. I just find it cleaner this way.

提交回复
热议问题