在 angular `redirectTo` 中保留 `$location.search()`?
Preserve `$location.search()` in angular `redirectTo`?
如何用
保存$location.search()
$routeProvider.otherwise({redirectTo: xxx})
我知道,我可以在那里使用一个函数,它将旧对象 $location.search()
作为第三个参数。我主要关心一个键,我们称它为a
,我试过
function(a, b, search) {
return "/mainpage?a=" + search[a];
}
但它总是以 /mainpage?a=undefined
结尾。更糟糕的是,它使我的调试器崩溃,从而减慢了我的速度。此外,这不适用于所有键(我稍后可能需要)。
主要问题是,在配置阶段(.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 编译为默认路由 - BUT ngRoute 转义.
例如,defaultURL()
函数生成如下内容:/mainpage?a=123
。但是,ngRoute 会转义特殊字符(即 ?
和 &
),您会被重定向到 /mainpage%3Fa=123
,这不会按预期工作。
此外,这仅在您 新鲜 打开包含该 URL 的页面时有效。当您已经在页面上并更改为无效 URL 时,上述代码不起作用,因为配置阶段已经完成 - .config()
每次页面加载仅触发一次。
TL;DR
据我所知,这不能通过在配置阶段使用 $routeProvider.otherwise()
方法来完成。
您可以创建自己的 provider
,并在 config
和 run
阶段进行连接,以保留您的搜索参数。
假设您有以下条件:
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
。
相关插件在这里http://plnkr.co/edit/cqR2Nh
我采用了一种新方法,如果上一个(不存在的)页面包含 重要,您可以在其中监听 $routeChangeStart
并修改 search()
获取参数。可以在 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'],
});
演示
第一个 link 在不存在的 URL 上包含 3 个参数。页面被正确重定向到默认路由,并且只保留了 2 个重要的路由。
second 和 fourth links 不包含任何参数,并且 links 都没有' 应用任何附加参数(无论您在单击它们时位于哪个页面)。
third link 也包含默认路由上的 3 个参数,所有参数都被保留(没有重定向发生)。
如何用
保存$location.search()
$routeProvider.otherwise({redirectTo: xxx})
我知道,我可以在那里使用一个函数,它将旧对象 $location.search()
作为第三个参数。我主要关心一个键,我们称它为a
,我试过
function(a, b, search) {
return "/mainpage?a=" + search[a];
}
但它总是以 /mainpage?a=undefined
结尾。更糟糕的是,它使我的调试器崩溃,从而减慢了我的速度。此外,这不适用于所有键(我稍后可能需要)。
主要问题是,在配置阶段(.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 编译为默认路由 - BUT ngRoute 转义.
例如,defaultURL()
函数生成如下内容:/mainpage?a=123
。但是,ngRoute 会转义特殊字符(即 ?
和 &
),您会被重定向到 /mainpage%3Fa=123
,这不会按预期工作。
此外,这仅在您 新鲜 打开包含该 URL 的页面时有效。当您已经在页面上并更改为无效 URL 时,上述代码不起作用,因为配置阶段已经完成 - .config()
每次页面加载仅触发一次。
TL;DR
据我所知,这不能通过在配置阶段使用 $routeProvider.otherwise()
方法来完成。
您可以创建自己的 provider
,并在 config
和 run
阶段进行连接,以保留您的搜索参数。
假设您有以下条件:
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
。
相关插件在这里http://plnkr.co/edit/cqR2Nh
我采用了一种新方法,如果上一个(不存在的)页面包含 重要,您可以在其中监听 $routeChangeStart
并修改 search()
获取参数。可以在 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'],
});
演示
第一个 link 在不存在的 URL 上包含 3 个参数。页面被正确重定向到默认路由,并且只保留了 2 个重要的路由。
second 和 fourth links 不包含任何参数,并且 links 都没有' 应用任何附加参数(无论您在单击它们时位于哪个页面)。
third link 也包含默认路由上的 3 个参数,所有参数都被保留(没有重定向发生)。