event.preventDefault()在.then内部不起作用

时间:2015-08-11 22:04:07

标签: javascript angularjs events angular-ui-router angular-promise

代码:

angular
  .module('mean-starter')
  .run(run)
;

function run($rootScope, Auth, $state) {
  function preventStateChange (message, event, redirect) {
    console.log(event);
    event.preventDefault();
    alert(message);

    if (redirect) {
      $state.go(redirect);
    }
  }

  $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
    if (typeof toState.authenticate === 'undefined') { // this route doesn't require permissions
      return;
    }

    event.preventDefault(); // WORKS HERE

    Auth
      .getCurrentUser()
      .then(function (currentUser) {
        event.preventDefault(); // DOESN'T WORK HERE
        var isLoggedIn = !!currentUser._id;
        var isAdmin = isLoggedIn && currentUser.role === 'admin';
        var isAuthorized = isLoggedIn && currentUser._id.toString() === toParams.id;

        if (toState.authenticate.loggedOut && isLoggedIn) { // this route requires you to be logged out
          preventStateChange("You're logged in.", event);
        }
        else if (!isLoggedIn) {
          preventStateChange('Must be logged in to access this route.', event, 'login');
        }
        else if (toState.authenticate.authorized && !isAuthorized && !isAdmin) {
          preventStateChange('You are not authorized to access that route.', event);
        }
        else if (toState.authenticate.isAdmin && !isAdmin) {
          debugger;
          event.preventDefault();
          preventStateChange('You must be an admin to access this route.', event);
        }
      })
    ;
  });
}

当我以非管理员身份登录时,我转到localhost:3000/admin

  1. 我收到提醒说,"您必须是管理员才能访问此路线。"
  2. 我被带到管理页面,可以看到我不应该看到的所有管理员资料。
  3. 为什么会这样?

    当我在调试器中检查时,event.preventDefault被定义,似乎被调用。这是注销到控制台的event对象:

    enter image description here

    它的defaultPrevented属性设置为true

    更新:它在.then之外工作,但它在.then内部不起作用。这是令人惊讶的,因为它是在.then内定义的。

    更新2:我的猜测是event在到达.then之前执行了默认操作。基本上,.then为时已晚。

1 个答案:

答案 0 :(得分:1)

你的第二个猜测基本上是正确的。在返回所有当前事件处理程序后解析浏览器操作。实际上,防止默认操作(实际上是原始机制)的一种机制是让事件处理程序返回false0来取消默认操作。所以它是半同步发生的 - 它发生在异步函数中,但在当前事件循环结束时解析。

解决这个问题的唯一方法是在致电承诺之前致电.preventDefault()