【问题标题】:$stateChangeStart event continuing after state change$stateChangeStart 事件在状态更改后继续
【发布时间】:2014-12-20 13:27:27
【问题描述】:

我正在尝试使用以下命令将用户发送到 Angular 中的特定“关闭”UI 状态:

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
  // check the destination is active
  if(toState.data.isClosed) { // note that the 'closed' state has isClosed set to false
    event.preventDefault();
    $state.go('closed');
  }
  $rootScope.data = toState.data;  // getting executed twice after our state transition to 'closed'
  $log.debug(toState);
});

我遇到的问题是$rootScope.data = toState.data 在我们转换到“关闭”状态后被调用了两次。

$startChangeStart 在路由器中设置data.isClosed = true 导航到我们的“订单”状态时,第一次执行$startChangeStart,状态更改为“关闭”并且相关代码不会被执行。

当我们现在将状态更改为“关闭”时,$startChangeStart 再次被触发,相关代码第一次执行,其中 toState 是我们的“关闭”状态。

奇怪的是,代码随后被执行,在 if() 逻辑之后开始,toState 是 'order' 的原始状态......这意味着当所有内容都加载完毕时,$rootScope.data 变量包含来自“订单”而不是“关闭”。添加几个断点,上面的调试代码就确认了。

有什么解释吗?

更新

由于状态转换到“关闭”状态的执行模式,我添加了一个返回以确保在 $state.go() 调用终止后继续执行。修改后的代码:

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
  // check the destination is active
  if(toState.data.isClosed) { // note that the 'closed' state has isClosed set to false
    event.preventDefault();
    $state.go('closed');
    return;
  }
  $rootScope.data = toState.data;  // getting executed twice after our state transition to 'closed'
  $log.debug(toState);
});

现在按预期工作,但我不确定它是否“正确”。

【问题讨论】:

  • 你能在 PLNKR 中重现这个吗?这里似乎没有发生:plnkr.co/edit/30IohTOqPHbOcGluMzaX?
  • 您的 plnkr 似乎并没有真正转换状态 - 在 $state.transitionTo() 之后立即触发发布和退出警报并且仍然包含 state2 数据 - plnkr.co/edit/loDq6xNmONBDRCTlQe8H
  • 在状态更改处理程序中这样做似乎有点奇怪。也许你可以使用重定向来做到这一点?

标签: angularjs angular-ui-router


【解决方案1】:

return 语句的解决方案简单正确。我创建了this playground,您可以在其中进行测试。

让我们拥有这些状态。首先是一些带有 isClosed false 的状态 - 这不应该由我们的事件监听器管理

  .state('state1', {
    url: "/state1",
    template: "<div>this is a state1</div>",
    data: { isClosed : false },
  })
  .state('state2', {
    url: "/state2",
    template: "<div>this is a state2</div>",
    data: { isClosed : false },
  })

这些将被捕获并重定向

  .state('stateClosed1', {
    url: "/stateClosed1",
    template: "<div>this is a stateClosed1</div>",
    data: { isClosed : true },
  })
  .state('stateClosed2', {
    url: "/stateClosed2",
    template: "<div>this is a stateClosed2</div>",
    data: { isClosed : true },
  })
  // even this would be handy
  .state('closed', {
    url: "/closed",
    template: "<div>this is a closed</div>",
    data: { isClosed : false },
  })

现在,每当我们进入任何状态时,都会触发事件 $stateChangeStart。因此,如果我们进入“未处理”状态 (state1, state2) - 该事件将被触发一次。

如果我们进入已处理状态(stateClosed1, stateClosed2),事件总是会触发两次:

  • 转到 stateClosed1
  • 去关闭

只是为了确定:事件确实被触发了两次。这就是为什么我们应该像这样编写这些监听器的原因(尽快离开)

  $rootScope.$on('$stateChangeStart', function(event, toState, toParams
                                                    , fromState, fromParams) {

    // get out if we already go to state, which is about to be handled below
    if(toState.name === "closed") {
      return;
    }

    // check the destination is active
    if (toState.data.isClosed) { // note that the 'closed' 
      event.preventDefault();    // state has isClosed set to false 
      $state.go('closed');
      return; 
    }
    $rootScope.data = toState.data; // getting executed 'closed'
                                    // twice after our state transition to 
                                    // only if above if does not contain return
    console.debug(toState);
  });

事实上,这个解决方案(尽快退出)是这些问答中的问题:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-15
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多