【问题标题】:Pass URL to as $routeParam in AngularJS app在 AngularJS 应用程序中将 URL 作为 $routeParam 传递
【发布时间】:2013-04-21 19:39:04
【问题描述】:

如何将实际 URL(带有斜杠、逗号等)作为 $routeParam 传递给 AngularJS 应用程序?

这将起作用: http://paprikka.github.io/le-bat/#/preview/asdadasda

这不会: http://paprikka.github.io/le-bat/#/preview/http://page.com

这也不会: http://paprikka.github.io/le-bat/#/preview/http%3A%2F%2Fpage.com

或者这个: http://paprikka.github.io/le-bat/#/preview/?url=http%3A%2F%2Fpage.com

详情

AngularJS 路由机制的设计不允许将带有斜杠的字符串作为查询参数传递。我可以理解这个决定背后的原因——我们不想在这里创建无状态服务器。

但是,在某些情况下,可能需要在路由中使用不同的分隔符或正则表达式。

我想创建一个应用程序,它采用 url 哈希字符串参数并将其内容加载到 iframe (link here)。路由以非常标准的方式设置(我使用的是 Coffeescript,但这个 sn-p 与纯 js 没有区别):

$routeProvider
  .when('/preview/:src', {templateUrl: 'partials/preview.html',
  controller: 'PreviewCtrl'})
  .when('/preview', {templateUrl: 'partials/preview.html',
  controller: 'PreviewCtrl'})

当然,我可以在 AngularJS 启动之前从哈希中加载 url,然后将其传递给库,但如果我还可以在更改范围内的数据时更新当前路由参数,那就太好了 - 这就是为什么我认为它更好不要避免使用 AngularJS API。

【问题讨论】:

  • 抱歉,我没听清问题是什么?
  • 嗯..我已经用更简洁的问题描述更新了这个问题。看看我添加的链接(希望这不会被视为垃圾邮件:))
  • 你不能只使用查询参数样式编码吗?喜欢http://example.com/#/preview/?url=http://page.com。另见:docs.angularjs.org/api/ng.$routeParams
  • 好吧,我不会问我是否可以:) 你检查了演示吗?而且,当然 - 我已经阅读了文档。
  • 啊,当然,这就是问题所在!您是否尝试过使用encodeURIComponent 转义网址?结果类似于http://example.com/#/preview/?url=http:%3A%2F%2Fpage.com

标签: javascript angularjs url-routing


【解决方案1】:

在 Angular 1.2 中使用 $routeProvider,如果 URL 位于路径的末尾,您可以通过在模式中添加星号来传递它。无论您是否对 URL 进行 URLComponentEncode,以下操作都应该有效。

路线:

angular.module('angularApp', ['ngRoute'])
      .when('/frame/:picture_url*', {
        templateUrl: 'views/frame.html',
        controller: 'PictureFrame'
      });

控制器:

      .controller('PictureFrame', function($scope, $routeParams, $sce){
        //whitelist the URL
        $scope.picture_url = $sce.trustAsResourceUrl($routeParams.picture_url);
      });

然后在你的模板中:

<iframe ng-src="{{picture_url}}"></iframe>

【讨论】:

  • 这对我不起作用。传递 URL 时路由仍然不匹配。
【解决方案2】:

好的,我已经设法找到一个适用于当前稳定版本 (@1.0.7) 的解决方案。

当前处理此问题的方法将涉及与 $route 相关的事件、动态解析 angular-incompatible url 并通过以类似于 $http 拦截的方式工作的附加服务来处理它们。

您可以在此处查看工作代码示例:http://embed.plnkr.co/fIA2xj/preview

主要步骤

  1. 像往常一样传递一个角度不兼容的 url,例如。转到 site.com/url/http://site.com
  2. 监听 $routeChangeStart 事件并为以/url/ 开头的路径提取正确的 url 参数
  3. 将正确的 url 参数编码为角度兼容的形式(在这种特殊情况下,我使用 base64)。不要使用 encodeURIComponent,因为 Angular 将视为任何其他 url
  4. 使用您的业务逻辑重定向到另一条路线,例如。 site.com/parsed-url/BASE64_GOES_HERE
  5. 在控制器中解码 URL 并像往常一样使用它:)

代码

照常创建 Angular 应用模块

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 拦截器服务(单例)

.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
  }
})

控制器

// 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);
});

你应该记住两件事:

  1. 尽管我尝试创建一个尽可能干净的解决方案,但通常以这种方式将数据传递给 angular 并不是一个好的做法,因此除非确实需要,否则尽量不要使用它。
  2. 您可以仅使用一条路由来处理此问题。我只是觉得这样更干净。

【讨论】:

  • base64 不支持日文字符,所以我正在寻找另一种编码格式。
【解决方案3】:

我有一个解决方案,但我不知道它是否会对您有所帮助。来自 Angular 文档http://docs.angularjs.org/api/ng.$location $location 有一个函数 search(search, paramValue)

传递参数:

parameter = encodeURIComponent url
$location.search({ yourURLParameter: parameter }).path('/preview')

读取参数:

url = decodeURIComponent $location.search().yourURLParameter

当然需要注入$location依赖

【讨论】:

  • 谢谢,但是我们已经测试了 encodeURIComponent 并且它也不起作用。
【解决方案4】:

我将搜索参数与路线混合在一起。您的搜索需要在您的路线之前进行。特别是对于较旧的浏览器。如果不是url/?search/#/hash,我认为ie7 会爆炸。

试试这个格式:

domain.com/?my=params&another=param/#/my/hashes

【讨论】:

  • 这很酷,但是搜索和路由是由前端完成的。很抱歉,但我不得不否决您的回答 :( 有人建议在 url 片段中使用查询样式的参数,但这也不是一个好主意。无论如何,感谢您抽出宝贵时间。
猜你喜欢
  • 2018-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
  • 2015-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
相关资源
最近更新 更多