AngularJS UI 路由器-无需重新加载状态更改 URL

目前,我们的项目是使用默认的 $routeProvider,我使用这个“黑客”,改变 url没有重新加载页面:

services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}]);

以及 controller

$locationEx.skipReload().path("/category/" + $scope.model.id).replace();

我正在考虑用 ui-router代替 routeProvider作为嵌套路线,但是在 ui-router中找不到这个。

有没有可能——对 angular-ui-router做同样的事情?

我为什么需要这个? 让我用一个例子来解释:
创建新类别的路由是 /category/new 在保存 clicking之后,我展示了 success-alert,我想把路由 /category/new改为 /caterogy/23(23-是存储在 db 中的新项目的 id)

128596 次浏览

我觉得你根本不需要 ui 路由器。可用于 $定位服务的文档在第一段中说,“ ... 对 $location 的更改反映在浏览器地址栏中。”后来它继续说,“它没有做什么?当浏览器 URL 更改时,它不会导致整个页面重新加载。”

因此,考虑到这一点,为什么不简单地改变 $location.path (因为该方法既是 getter 方法,也是 setter 方法) ,如下所示:

var newPath = IdFromService;
$location.path(newPath);

文件指出,路径应该始终以斜杠开头,但如果缺少斜杠,则添加斜杠。

好了,解决了 Angular UI 路由器有这个新方法,$urlRouterProvider.deferIntercept () Https://github.com/angular-ui/ui-router/issues/64

基本上就是这样:

angular.module('myApp', [ui.router])
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}])
// then define the interception
.run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();


/**
* provide conditions on when to
* sync change in $location.path() with state reload.
* I use $location and $state as examples, but
* You can do any logic
* before syncing OR stop syncing all together.
*/


if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
// your stuff
$urlRouter.sync();
} else {
// don't sync
}
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
}]);

我认为这种方法目前只包括在 师父版本的棱角 ui 路由器,一个可选的参数(顺便说一句,这也很好)。它需要从源代码进行克隆和构建

grunt build

文档也可以从源代码访问,通过

grunt ngdocs

(它们内置在/site 目录中)//更多信息,请参见 README.MD

似乎有另一种方法可以做到这一点,通过动态参数 (我还没有使用过)。 多亏了 Nateabele。


作为一个旁注,下面是 Angular UI 路由器的 $stateProvider 中的 可选参数,我将它与上面的结合使用:

angular.module('myApp').config(['$stateProvider', function ($stateProvider) {


$stateProvider
.state('main.doorsList', {
url: 'doors',
controller: DoorsListCtrl,
resolve: DoorsListCtrl.resolve,
templateUrl: '/modules/doors/doors-list.html'
})
.state('main.doorsSingle', {
url: 'doors/:doorsSingle/:doorsDetail',
params: {
// as of today, it was unclear how to define a required parameter (more below)
doorsSingle: {value: null},
doorsDetail: {value: null}
},
controller: DoorsSingleCtrl,
resolve: DoorsSingleCtrl.resolve,
templateUrl: '/modules/doors/doors-single.html'
});


}]);

它允许解析一个状态,即使其中一个参数丢失了。 搜索引擎优化是一个目的,可读性是另一个目的。

在上面的示例中,我希望 door sSingle 是一个必需的参数。目前尚不清楚如何定义这些问题。不过,它可以使用多个可选参数,所以这不是一个问题。讨论在这里 https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

您可以简单地使用 $state.transitionTo 而不是 $state.go $state.go 在内部调用 $state.transitionTo ,但自动将选项设置为 { location: true, inherit: true, relative: $state.$current, notify: true } 。您可以调用 $state.transitionTo 并设置 notify: false 。例如:

$state.go('.detail', {id: newId})

可以被

$state.transitionTo('.detail', {id: newId}, {
location: true,
inherit: true,
relative: $state.$current,
notify: false
})

编辑: 正如 fraz 建议的那样,它可以简单地是:

$state.go('.detail', {id: newId}, {notify: false})

这个设置为我解决了以下问题:

  • 在将 URL 从 .../更新到 .../123时,不会调用训练控制器两次
  • 当导航到另一个状态时,不再调用训练控制器

状态配置

state('training', {
abstract: true,
url: '/training',
templateUrl: 'partials/training.html',
controller: 'TrainingController'
}).
state('training.edit', {
url: '/:trainingId'
}).
state('training.new', {
url: '/{trainingId}',
// Optional Parameter
params: {
trainingId: null
}
})

调用 state (来自任何其他控制器)

$scope.editTraining = function (training) {
$state.go('training.edit', { trainingId: training.id });
};


$scope.newTraining = function () {
$state.go('training.new', { });
};

培训总监

var newTraining;


if (!!!$state.params.trainingId) {


// new


newTraining = // create new training ...


// Update the URL without reloading the controller
$state.go('training.edit',
{
trainingId : newTraining.id
},
{
location: 'replace', //  update url and replace
inherit: false,
notify: false
});


} else {


// edit


// load existing training ...
}

在这个问题上花了很多时间之后,以下是我得到的工作

$state.go('stateName',params,{
// prevent the events onStart and onSuccess from firing
notify:false,
// prevent reload of the current state
reload:false,
// replace the last record when changing the params so you don't hit the back button and get old params
location:'replace',
// inherit the current params on the url
inherit:true
});

我在很久以前的版本: v0.2.10的 UI-router 中就是这样做的:

$stateProvider
.state(
'home', {
url: '/home',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
controller: 'mainCtrl'
},
}
})
.state('home.login', {
url: '/login',
templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
controller: 'authenticationCtrl'
})
.state('home.logout', {
url: '/logout/:state',
controller: 'authenticationCtrl'
})
.state('home.reservationChart', {
url: '/reservations/?vw',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
controller: 'reservationChartCtrl',
reloadOnSearch: false
},
'viewVoucher@home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
controller: 'viewVoucherCtrl',
reloadOnSearch: false
},
'addEditVoucher@home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
controller: 'voucherCtrl',
reloadOnSearch: false
}
},
reloadOnSearch: false
})

如果您只需要更改 url 但不需要更改状态:

使用以下命令更改位置(如果希望在历史记录中进行替换,则添加. Change) :

this.$location.path([Your path]).replace();

防止重定向到您的状态:

$transitions.onBefore({}, function($transition$) {
if ($transition$.$to().name === '[state name]') {
return false;
}
});

试试这个

$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})

呼叫

$state.go($state.current, {myParam: newValue}, {notify: false});

将仍然重新加载控制器,这意味着您将 丢失状态数据

为了避免这种情况,只需将参数声明为动态的:

$stateProvider.state({
name: 'myState',
url: '/my_state?myParam',
params: {
myParam: {
dynamic: true,    // <----------
}
},
...
});

然后你甚至不需要 notify,只需要打电话

$state.go($state.current, {myParam: newValue})

够了,太棒了!

来自 文件:

dynamictrue时,对参数值的更改将 不会导致进入/退出状态。解析将不会 重新获取,也不会重新加载视图。

这对于构建 组件在参数值更改时更新自身的 UI。

在角2中,RezKesh 的公认答案翻译如下:

this.uiRouter.stateService.go(
"home.myRouteState",
{
"param1": this.myParam1,
"param2": this.myParam2
},
{ notify: false }
);

假设您已经像下面这样在组件的构造函数中注入了 UIRout:

constructor(
private uiRouter: UIRouter
) { }