【问题标题】:Preserve `$location.search()` in angular `redirectTo`?在角度“redirectTo”中保留“$location.search()”?
【发布时间】:2015-06-09 13:26:28
【问题描述】:

我怎样才能保留$location.search()

$routeProvider.otherwise({redirectTo: xxx})

我知道,我可以在那里使用一个函数,它将旧对象 $location.search() 作为第三个参数。我主要关心一个键,我们称之为a,我试过了

function(a, b, search) {
    return "/mainpage?a=" + search[a];
}

但它总是以/mainpage?a=undefined 结尾。更糟糕的是,它使我的调试器崩溃,这让我放慢了速度。此外,这不适用于所有键(我以后可能需要)。

【问题讨论】:

    标签: javascript angularjs routes


    【解决方案1】:

    我采用了一种新方法,您可以在其中侦听$routeChangeStart 并修改search(),如果之前的(不存在的)页面包含重要 GET 参数。完整的源代码和演示可以在 this Plunker 上找到。

    概念类似于@Mikko 的解决方案,但实现有点不同(没有自定义提供程序),它按照作者的说明工作。

    本质

    angular.module('myApp').run(['$rootScope', '$location', 'URL', function($rootScope, $location, URL) {
    
        // Previous search() value
        var prevSearch = {};
    
        // Listen to event
        $rootScope.$on('$routeChangeStart', function(evt, next, current) {
    
            // Have search() parameters and are going to default route
            if(prevSearch !== undefined && $location.path().endsWith(URL.defaultRoute)) {
    
                // Extract only important params
                var important = {};
                var importantCount = 0;
    
                for(var param in prevSearch) {
    
                    if(URL.importantParams.indexOf(param) > -1) {
    
                        important[param] = prevSearch[param];
                        importantCount++;
    
                    }
    
                }
    
                // Unset prevSearch
                prevSearch = {};
    
                // Apply important params, if any
                if(importantCount > 0) {
    
                    $location.search(important);
    
                }
    
    
            } else {
    
                // Remember current search()
                prevSearch = $location.search();
    
            }
    
        });
    
    }]);
    

    run 函数为$routeChangeStart 设置了一个侦听器,并且还记住了search() 值的先前值(GET 参数)。

    当应用程序被重定向到默认路由时,它会检查 search() 参数的先前值并仅提取重要的参数。如果有的话,它会覆盖 search() 值,因此将重要的 GET 参数设置为默认路由。

    我制作了一个URL 常量,可以在其中设置默认路由并指定重要参数。代码如下:

    angular.module('myApp').constant('URL', {
        defaultRoute: '/mainpage',
        importantParams: ['a', 'b'],
    });
    

    演示

    first 链接在一个不存在的 URL 上包含 3 个参数。页面被正确重定向到默认路由,并且只保留了 2 个重要的。

    secondfourth 链接不包含任何参数,并且两个链接都不应用任何附加参数(无论您在哪个页面上单击它们) .

    第三个​​链接还包含默认路由上的 3 个参数,所有参数都被保留(不发生重定向)。

    【讨论】:

    • 很高兴听到我启发了某人:)!除了可重用性,不应该从Default URL with params 导航到例如Non-existing URL without params 还保留参数吗?换句话说,不存在的 url,不管有没有参数,都应该使用最后一个已知的“好”路由的参数重定向到main
    • 我接受了这个答案,因为它更简单,并将赏金授予@MikkoViitala,因为他是第一个。 +++关于使用最后一个已知的“好”路线的参数,我实际上不在乎。用户来自其他地方,使用指向http://example.com?important=42 的链接,我必须将他们重定向到http://example.com/main?important=42。类似的情况是http://example.com/non-existing-page?important=42。这就是我现在所需要的,还没有考虑过更复杂的情况。谢谢你们!
    【解决方案2】:

    主要问题是,在配置阶段(.config() 函数),您只能注入提供程序。由于$location 不是提供者,因此您无法注入它。因此$location.search() 不起作用。

    但是,您可以使用纯 JavaScript 的 window.location.hash 来获取 URL 参数。但是,这不是 Angular 的方式,它不会像你希望的那样工作。

    例如,如果您使用以下配置代码:

    angular.module('myApp').config(['$routeProvider', function($routeProvider) {
    
        // Return $location.search() equivalent object
        function locationSearch() {
    
            var search = {};
            var hash = window.location.hash;
            var index = hash.indexOf('?');
    
            // Has parameters
            if(index > -1) {
    
                // Extract only the params
                var params = hash.substring(index + 1);
    
                // Split parameters
                params = params.split('&');
    
                var tmp;
                for(var i = 0, len = params.length; i < len; i++) {
    
                    tmp = params[i].split('=');
                    search[tmp[0]] = tmp[1];
    
                }
    
            }
    
            return search;
    
        }
    
        // Generate default URL
        function defaultURL(search) {
    
            if(search.a === undefined) {
    
                return '/mainpage';
    
            } else {
    
                return '/mainpage?a=' + search.a;
    
            }
    
        }
    
        // Equivalent of $location.search()
        var search = locationSearch();
    
        // Set up routing
        $routeProvider
    
            // Events
            .when('/test', {
                templateUrl: 'test.html',
                controller: 'TestCtrl'
            })
    
            // Default page
            .otherwise({
                redirectTo: defaultURL(search)
            });
    
    }]);
    

    使用上面的代码,您可以访问$location.search() 的等效项,并将动态 URL 编译为默认路由 - 但是 ngRoute 将其转义。 p>

    例如,defaultURL() 函数会产生如下内容:/mainpage?a=123。但是,ngRoute 会转义特殊字符(即?&amp;),您会被重定向到/mainpage%3Fa=123,这无法按预期工作。

    此外,这仅在您打开具有该 URL 的页面时有效。当您已经在页面上并更改为无效 URL 时,上述代码不起作用,因为配置阶段已经完成 - .config() 每次页面加载仅触发一次。

    TL;DR

    据我所知,这不能通过在配置阶段使用 $routeProvider.otherwise() 方法来完成。

    【讨论】:

      【解决方案3】:

      您可以创建自己的provider,在configrun 阶段进行连接,以保留您的搜索参数。

      假设您有以下内容:

      angular.module('app', ['ngRoute'])
        .provider('myRoute', function myRouteProvider() {
          var defaultUrl;
          var search;
      
          // get default url with params (config phase)
          this.default = function() {
            var params = '';
            angular.forEach(search, function(value, key) {
              params = params + key + '=' + value + '&';
            });
      
            if (params.length > 0) {
              params = params.substring(0, params.length - 1);
            }
      
            var redirectUrl = defaultUrl + (params ? '?' + params : '');
            console.log(redirectUrl);
            return redirectUrl;
          };
      
          this.$get = function($rootScope) {
            var myRoute = {};
      
            // set default url (run phase)
            myRoute.setDefault = function(url) {
              if (defaultUrl) {
                throw 'Provider already initialized';
              }
      
              defaultUrl = url;
      
              // update params on route change
              $rootScope.$on('$routeChangeStart', function(event, next, current) {
                search = current.params;
              });
            };
      
            return myRoute;      
          };
        }) 
      
        .config(function($routeProvider, myRouteProvider) {
          $routeProvider
            .when('/main', {
              templateUrl: 'template.html',
              controller: 'Ctrl'
            })
            .when('/route1', {
              templateUrl: 'template.html',
              controller: 'Ctrl'
            })
            .when('/route2', {
              templateUrl: 'template.html',
              controller: 'Ctrl'
            })
            .otherwise({
              // redirect to default url with latest params
              redirectTo: myRouteProvider.default
            });
        })
      
        .run(function(myRoute) {
          // set default url (404)
          myRoute.setDefault('/main');
        })
      
        .controller('Ctrl', function($scope, $location) {
          $scope.$location = $location;
        });
      

      index.html 仅包含其中

      <div>
        <a href="#/main">main</a><br>
        <a href="#/route1">route1</a><br>
        <a href="#/route2?param=abc">route2?param=abc</a><br>
        <a href="#/404">otherwise</a><br>
      </div>
      <hr>
      <div ng-view></div> 
      

      和路线的template.html 很简单

      <div>
        path: {{ $location.path() }}
        <br>
        params: {{ $location.search() }}
      </div>
      

      现在,如果您在链接之间导航并点击 othwerwise,您将被重定向到 /main 以及之前路由中的任何 params


      相关的plunker在这里http://plnkr.co/edit/cqR2Nh

      【讨论】:

      • 我接受了另一个答案,因为它更简单,并像您一样将赏金授予您。对我来说,有必要做这些事情的事实看起来像是一个有角的错误。
      猜你喜欢
      • 2020-02-26
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-28
      • 1970-01-01
      相关资源
      最近更新 更多