如何在 ui-router 中将浏览器上的可选状态参数持久化?
How to persist optional state parameter on browser back in ui-router?
我有一个父状态,其中有两个子状态,我将根据 URL
.
显示一个状态
在这两个 states
中,一个必须使用 param1
和 param2
之类的参数,我在内部使用了 ui-router 的 params
选项状态定义。
州
$stateProvider.state('tabs.account', {
url: '/account',
views: {
'content@tabs': {
templateUrl: 'account.html',
controller: function($scope, $stateParams) {
//This params are internally used to make ajax and show some data.
$scope.param1 = $stateParams.param1;
$scope.param2 = $stateParams.param2;
},
}
},
params: {
param1: { value: null }, //this are optional param
param2: { value: null } //because they are not used in url
}
});
如果您查看我的路线,URL
中并未真正引入 params 选项,这就是为什么我将 then 视为可选的原因。
问题
看看 plunkr,我显示了两个选项卡 Account & Survey,
- 单击“调查”选项卡,然后在显示的
textarea
中添加一些数据。
单击 转到帐户,这会将那些 textarea
值传递给
另一个 Account 选项卡通过在 anchor
上执行 ui-sref="tabs.account({param1: thing1, param2: thing2})"
现在您将看到 html 上的 param1
和 param2
值已分配给 $stateParams
的范围
- 现在再次单击调查选项卡,您将进入调查页面。
- 只需单击浏览器返回,您会注意到
param
值没有得到 null
。
相信你已经明白我想问的了,为什么可选参数值没有被存储?因为他们是国家的一部分。
我知道我可以通过以下两种解决方案解决这个问题。
- 通过创建一个将在两个视图之间共享数据的服务。
- 通过在状态中添加参数URL。喜欢
url: '/account/:param1/:param2',
(但我不喜欢这个)
我已经尝试过 angular-ui-routers sticky states
但这似乎对我不起作用。什么是更好的方法?
有什么方法可以使我的用例正常工作,任何想法都将不胜感激。
Github Issue Link Here
我相信如果不使用您提供的两种解决方案中的一种,您将无法实现您想要实现的目标。
浏览器后退按钮仅保留 URL 历史记录。他对 ui-路由器内部状态一无所知,只会强制 URL 改变。
强制 URL 改变会触发内部 ui-router 机器,但不幸的是 ui-router 会看到 URL 改变,就像有人会手动更改 url。
Ui-router 将触发一个新的路由更改到 URL 指向的路由。这意味着他不知道你想去 "back" 并且只会在没有任何参数的情况下将状态更改为新状态。
总结
单击后退按钮将根据 URL 将状态更改为 新 状态,而不是返回到之前的状态。
这就是将参数添加到 URL 解决问题的原因。由于 URL 具有歧视性,您最终会到达您想要的状态。
希望对您有所帮助。
一个解决方法 解决方案是缓存状态参数并在进入tabs.account
状态时有条件地加载它们。 UI 路由器状态配置实际上允许您为这些类型的 "do something on entering the state" 情况提供 onEnter
回调。
这是使用 localStorage as the cache, with working Plunker here 的基本逻辑:
- 当您进入
tabs.account
状态时,检查您的状态参数
- 如果有,将它们缓存到本地存储
- 如果不这样做,请将它们从本地存储加载到
$stateParams
这里有一个示例代码片段供参考(取自 Plunker):
$stateProvider.state('tabs.account', {
...
onEnter: ['$stateParams', '$window', function($stateParams, $window) {
if($stateParams.param1) {
$window.localStorage.setItem('tabs.account.param1', $stateParams.param1);
} else {
$stateParams.param1 = $window.localStorage.getItem('tabs.account.param1');
}
if($stateParams.param2) {
$window.localStorage.setItem('tabs.account.param2', $stateParams.param2);
} else {
$stateParams.param2 = $window.localStorage.getItem('tabs.account.param2');
}
}],
...
}
一个 警告 是您的参数将无限期保留(例如,跨刷新和会话)。要解决此问题,您可以像 app.run
.
那样在应用程序加载时清除缓存
最后要注意的是,在 Plunker 中,我正在直接访问本地存储(通过 Angular $window
服务)。您可能想使用一些 AngularJS 模块 - 我在生产中使用了 angular-local-storage。
我会将 params
定义移至父状态,以便在您的两个子状态之间共享可选状态参数。
子状态将从您的父状态继承 $stateParams
,因此不需要真正的 'workaround'。
只需像往常一样在您的子控制器中注入 $stateParams
,您就可以完全访问传递的参数。如果您不想在特定子状态下使用参数,只需避免注入它们即可。
这适用于;
- 后退按钮
- 前进按钮
- ui-sref (没有参数(将保持原样))
- ui-sref (带有参数(将覆盖))
$stateProvider
.state('parent', {
params: { p1: null, p2: null }
})
.state('parent.childOne', {
url: '/one',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
.state('parent.childTwo', {
url: '/two',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
如果您在 parent
的状态树中移动时在任何时候想要 清除 参数,则必须 手动执行.
这将是 唯一 我可以通过使用此解决方案看到的真正警告。
我知道你提出的情况下可能不希望手动清除,但你没有采取积极的立场反对,所以我觉得这个建议是有价值的。
对我来说这听起来像 X Y problem。有一些建议的方法可以使状态参数持久化,而问题出在这个表面之外。
根据问题的定义,有些数据应该独立于状态。因此,相对于国家而言,它是一种全球性的。因此,应该有一个服务来保存它,并且两个状态的控制器都根据需要维护它。只是不要在状态参数中传递超出一个状态范围的数据。
粘性状态很适合这种方法,因为它允许在另一个状态处于活动状态时保持 DOM 和 $scope
。但是当状态被重新激活时,它与状态参数无关。
我有一个父状态,其中有两个子状态,我将根据 URL
.
在这两个 states
中,一个必须使用 param1
和 param2
之类的参数,我在内部使用了 ui-router 的 params
选项状态定义。
州
$stateProvider.state('tabs.account', {
url: '/account',
views: {
'content@tabs': {
templateUrl: 'account.html',
controller: function($scope, $stateParams) {
//This params are internally used to make ajax and show some data.
$scope.param1 = $stateParams.param1;
$scope.param2 = $stateParams.param2;
},
}
},
params: {
param1: { value: null }, //this are optional param
param2: { value: null } //because they are not used in url
}
});
如果您查看我的路线,URL
中并未真正引入 params 选项,这就是为什么我将 then 视为可选的原因。
问题
看看 plunkr,我显示了两个选项卡 Account & Survey,
- 单击“调查”选项卡,然后在显示的
textarea
中添加一些数据。 单击 转到帐户,这会将那些
textarea
值传递给 另一个 Account 选项卡通过在 anchor 上执行 现在您将看到 html 上的
的范围param1
和param2
值已分配给$stateParams
- 现在再次单击调查选项卡,您将进入调查页面。
- 只需单击浏览器返回,您会注意到
param
值没有得到null
。
ui-sref="tabs.account({param1: thing1, param2: thing2})"
相信你已经明白我想问的了,为什么可选参数值没有被存储?因为他们是国家的一部分。
我知道我可以通过以下两种解决方案解决这个问题。
- 通过创建一个将在两个视图之间共享数据的服务。
- 通过在状态中添加参数URL。喜欢
url: '/account/:param1/:param2',
(但我不喜欢这个)
我已经尝试过 angular-ui-routers sticky states
但这似乎对我不起作用。什么是更好的方法?
有什么方法可以使我的用例正常工作,任何想法都将不胜感激。
Github Issue Link Here
我相信如果不使用您提供的两种解决方案中的一种,您将无法实现您想要实现的目标。
浏览器后退按钮仅保留 URL 历史记录。他对 ui-路由器内部状态一无所知,只会强制 URL 改变。
强制 URL 改变会触发内部 ui-router 机器,但不幸的是 ui-router 会看到 URL 改变,就像有人会手动更改 url。
Ui-router 将触发一个新的路由更改到 URL 指向的路由。这意味着他不知道你想去 "back" 并且只会在没有任何参数的情况下将状态更改为新状态。
总结
单击后退按钮将根据 URL 将状态更改为 新 状态,而不是返回到之前的状态。
这就是将参数添加到 URL 解决问题的原因。由于 URL 具有歧视性,您最终会到达您想要的状态。
希望对您有所帮助。
一个解决方法 解决方案是缓存状态参数并在进入tabs.account
状态时有条件地加载它们。 UI 路由器状态配置实际上允许您为这些类型的 "do something on entering the state" 情况提供 onEnter
回调。
这是使用 localStorage as the cache, with working Plunker here 的基本逻辑:
- 当您进入
tabs.account
状态时,检查您的状态参数- 如果有,将它们缓存到本地存储
- 如果不这样做,请将它们从本地存储加载到
$stateParams
这里有一个示例代码片段供参考(取自 Plunker):
$stateProvider.state('tabs.account', {
...
onEnter: ['$stateParams', '$window', function($stateParams, $window) {
if($stateParams.param1) {
$window.localStorage.setItem('tabs.account.param1', $stateParams.param1);
} else {
$stateParams.param1 = $window.localStorage.getItem('tabs.account.param1');
}
if($stateParams.param2) {
$window.localStorage.setItem('tabs.account.param2', $stateParams.param2);
} else {
$stateParams.param2 = $window.localStorage.getItem('tabs.account.param2');
}
}],
...
}
一个 警告 是您的参数将无限期保留(例如,跨刷新和会话)。要解决此问题,您可以像 app.run
.
最后要注意的是,在 Plunker 中,我正在直接访问本地存储(通过 Angular $window
服务)。您可能想使用一些 AngularJS 模块 - 我在生产中使用了 angular-local-storage。
我会将 params
定义移至父状态,以便在您的两个子状态之间共享可选状态参数。
子状态将从您的父状态继承 $stateParams
,因此不需要真正的 'workaround'。
只需像往常一样在您的子控制器中注入 $stateParams
,您就可以完全访问传递的参数。如果您不想在特定子状态下使用参数,只需避免注入它们即可。
这适用于;
- 后退按钮
- 前进按钮
- ui-sref (没有参数(将保持原样))
- ui-sref (带有参数(将覆盖))
$stateProvider
.state('parent', {
params: { p1: null, p2: null }
})
.state('parent.childOne', {
url: '/one',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
.state('parent.childTwo', {
url: '/two',
controller: function ($stateParams) {
console.log($stateParams); // { p1: null, p2: null }
}
})
如果您在 parent
的状态树中移动时在任何时候想要 清除 参数,则必须 手动执行.
这将是 唯一 我可以通过使用此解决方案看到的真正警告。
我知道你提出的情况下可能不希望手动清除,但你没有采取积极的立场反对,所以我觉得这个建议是有价值的。
对我来说这听起来像 X Y problem。有一些建议的方法可以使状态参数持久化,而问题出在这个表面之外。
根据问题的定义,有些数据应该独立于状态。因此,相对于国家而言,它是一种全球性的。因此,应该有一个服务来保存它,并且两个状态的控制器都根据需要维护它。只是不要在状态参数中传递超出一个状态范围的数据。
粘性状态很适合这种方法,因为它允许在另一个状态处于活动状态时保持 DOM 和 $scope
。但是当状态被重新激活时,它与状态参数无关。