【问题标题】:How to persist optional state parameter on browser back in ui-router?如何在 ui-router 中保留浏览器上的可选状态参数?
【发布时间】:2015-10-11 03:19:25
【问题描述】:

我有一个父状态,其中包含两个子状态,我将根据 URL 显示一个状态。

在这两个states 中,一个必须使用param1param2 之类的参数,我在状态定义中使用了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,我展示了两个标签 AccountSurvey

  1. 单击“调查”选项卡,然后在textarea 中添加一些数据,如图所示。
  2. 点击Go to Account,将textarea 值传递给 另一个帐户标签,在锚点上执行ui-sref="tabs.account({param1: thing1, param2: thing2})"

  3. 现在您将在 html 上看到 param1param2 值,这些值已分配给 $stateParams 的范围

  4. 现在再次点击调查标签,您将进入调查页面。
  5. 点击浏览器返回,你会发现param的值没有得到null

Problem Plunkr

相信你已经明白我要问的了,为什么没有存储可选参数值?因为他们一直是国家的一部分。

我知道我可以通过以下两种解决方案来解决这个问题。

  • 通过创建一项将在两个视图之间共享数据的服务。
  • 通过在状态 URL 中添加参数。喜欢url: '/account/:param1/:param2',(但我不喜欢这个)

我已经尝试过 angular-ui-routers sticky states 但这似乎对我不起作用。有什么更好的方法?

有什么方法可以让我的用例正常工作,任何想法都会不胜感激。

Github Issue Link Here

【问题讨论】:

  • 刚刚发现这个github.com/angular-ui/ui-router/issues/1158关于“通知”属性可以设置为假以防止事件(例如重新加载控制器)但它实际上不起作用(错误)。
  • @Okazari 感谢您的评论..我也需要关注这个问题:(
  • 您是否考虑过使用查询参数而不是 url 参数?它可能有效,并且在 url ('/url/route?param1=value&param2=value') 中不会那么奇怪
  • @Okazari 谢谢你的建议,但我不想那样做..它基本上和我在这里做的一样
  • @downvoter 请在您投反对票时发表评论。有问题吗?

标签: javascript angularjs angular-ui-router angular-ui angularjs-routing


【解决方案1】:

我会将params 定义移动到父状态,以便在您的两个子状态之间共享可选状态参数。

子状态将从您的父状态继承 $stateParams,因此不需要真正的“解决方法”。

只需像往常一样在您的子控制器中注入$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 的状态树中移动时清除参数,您必须手动进行。

这将是我在使用此解决方案时可以看到的唯一真正的警告。

我知道在您提出的情况下,手动清除可能并不可取,但您并没有积极反对它,因此我认为这个建议是有道理的。

updated plunker

【讨论】:

  • 这也是一个很好的解决方案。请注意,如果您希望参数在从其他状态导航时保持不变(想象在应用程序或外部完全不同的地方,然后使用浏览器后退按钮 - 不确定这是否是您的一个用例)。
  • 如果你移动到一个没有参数概念的状态,参数不会持续存在,后退按钮也是如此。如果状态知道参数的到来,一切都很好。因此,您可以继续在状态层次结构中将单个参数定义打乱 - 但是当它开始变得愚蠢时,我会将其移至服务中。
  • 我设想的共享 参数 的用例是几个与传递的参数有逻辑联系的状态。如果我的想法是传递数据并将其保留在整个应用程序的大部分/整个应用程序中,我绝不会推荐使用它。
  • @KasperLewau 有什么建议我应该什么时候清除这些值..您对此有何想法?
  • @PankajParkar 好吧,由于您在包含 params 属性的父级的所有子状态之间共享值,因此一旦您从该状态树转换出来然后 in 再次,在入口时不传递参数。这真的取决于你的用例,你什么时候需要清除它?
【解决方案2】:

一个解决方法解决方案是缓存状态参数并在进入tabs.account 状态时有条件地加载它们。 UI Router 状态配置实际上允许您为这些类型的“进入状态时执行某些操作”情况提供onEnter 回调。

这是使用 localStorage 作为缓存的基本逻辑,使用 Plunker here

  • 当您进入tabs.account 状态时,检查您的状态参数
    • 如果有,请将它们缓存到本地存储中
    • 如果不这样做,请将它们从本地存储加载到 $stateParams

这是一个示例代码 sn-p 供参考(取自 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

【讨论】:

  • 如果您不想无限期地保留,只需使用 SessionStorage 而不是 LocalStorage。 sessionStorage 有一个应用会话的生命周期(刷新/关闭清除会话存储)
  • @Okazari sessionStorage/localStorage 是否可以在 IE9/IE10 等旧浏览器中使用?
  • @PankajParkar IE9/10 完全支持这两种技术。 caniuse?
  • @Okazari 这看起来很有希望..我会回到这个答案..经过我的一些测试
  • @KasperLewau 是的,我正在查看..目前我在这里没有我的代码..我肯定会在星期一早上查看它..我已经对你的答案投了赞成票.. :)
【解决方案3】:

我相信如果不使用您提供的两种解决方案之一,您想要实现的目标是不可能的。

浏览器后退按钮只是保留 URL 历史记录。他对 ui-router 内部状态一无所知,只会强制 URL 更改。

强制更改 URL 将触发内部 ui-router 机器,但不幸的是 ui-router 会看到 URL 更改,就像有人手动更改 url 一样。

Ui-router 将触发对 URL 指向的路由的新路由更改。这意味着他不知道您想“返回”,并且只会将状态更改为新的状态而无需任何参数。

总结

单击后退按钮将根据 URL 将状态更改为 状态,而不是返回到之前的状态。

这就是为什么将参数添加到 URL 可以解决问题的原因。由于 URL 具有歧视性,您最终会到达您想要的状态。

希望它有所帮助。

【讨论】:

  • 我知道我只能通过这两种解决方案来解决这个问题..我认为其中添加参数是不可取的,当我有多个参数时会变得一团糟..
  • @PankajParkar 那么您的服务解决方案可能就是其中之一。
  • 是的..但我正在寻找与我的想法不同的东西..一定有某种方式..这是我想念的..
【解决方案4】:

对我来说这听起来像X Y problem。有一些建议的方法可以使状态参数持久化,而问题不在此表面。

根据问题的定义,有一些数据应该独立于状态而保存。所以它相对于国家来说是一种全球性的。因此,应该有一个服务来保持它,并且两种状态的控制器都应该根据需要维护它。只是不要在状态参数中传递超出一个状态范围的数据。

粘性状态很容易适应这种方法,因为它允许在另一个状态处于活动状态时保持 DOM 和 $scope。但是当状态被重新激活时,它与状态参数无关。

【讨论】:

  • @krill 你能给我一个带有粘性状态的例子吗?我试过了,但这对我不起作用。谢谢:)
  • @PankajParkar 当然thing。对于这种情况,您甚至不需要来自 ui-router-extras 的粘性状态。如果您在更复杂的情况下需要帮助,请告诉我(我敢打赌您有真正的目的)
  • @krill 您制作的 plunkr 遵循了一种方法,即我在问题本身中建议的 服务方法
  • @PankajParkar 这确实是这项任务的最佳方法,我解释了原因。粘性解决方案看起来像this。你的问题是粘性状态应该占据different named ui-view each。但是,这种方法在单击菜单时不会将参数传输到account
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-22
相关资源
最近更新 更多