programing

앵귤러는?ui-router를 사용하는 JS는 $state를 계속 발사합니다.ChangeStart 이벤트?

mailnote 2023. 9. 23. 23:01
반응형

앵귤러는?ui-router를 사용하는 JS는 $state를 계속 발사합니다.ChangeStart 이벤트?

사용자를 인증하기 전까지 모든 ui-router 상태 변경을 차단하려고 합니다.

$rootScope.$on('$stateChangeStart', function (event, next, toParams) {
  if (!authenticated) {
    event.preventDefault()
    //following $timeout is emulating a backend $http.get('/auth/') request
    $timeout(function() {
      authenticated = true
      $state.go(next,toParams)
    },1000)
  }
})

사용자가 인증될 때까지 모든 상태 변경을 거부하지만, 사용하는 잘못된 URL로 이동하는 경우otherwise()구성, 메시지와 함께 무한 루프가 나타납니다.

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: $locationWatch; newVal: 7; oldVal: 6"],["fn: $locationWatch; newVal: 8; oldVal: 7"],["fn: $locationWatch; newVal: 9; oldVal: 8"],["fn: $locationWatch; newVal: 10; oldVal: 9"],["fn: $locationWatch; newVal: 11; oldVal: 10"]]

아래는 저의 SSCCE입니다.함께 제공합니다.python -m SimpleHTTPServer 7070그리고 가.localhost:7070/test.html#/bar네 얼굴에 폭발하는 걸 보는 거지반면에 유일하게 유효한 angularjs 위치로 직접 탐색하면 폭발하지 않습니다.localhost:7070/test.html#/foo:

<!doctype html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
  </head>
  <body ng-app="clientApp">
    <div ui-view="" ></div>

    <script>
      var app = angular.module('clientApp', ['ui.router'])

      var myRouteProvider = [
                '$stateProvider', '$urlRouterProvider',
        function($stateProvider,   $urlRouterProvider) { 
          $urlRouterProvider.otherwise('/foo');
          $stateProvider.state('/foo', {
            url: '/foo',
            template: '<div>In Foo now</div>',
            reloadOnSearch: false
          })
        }]
      app.config(myRouteProvider)

      var authenticated = false
      app.run([
                 '$rootScope', '$log','$state','$timeout',
        function ($rootScope,   $log,  $state,  $timeout) {
          $rootScope.$on('$stateChangeStart', function (event, next, toParams) {
            if (!authenticated) {
              event.preventDefault()
              //following $timeout is emulating a backend $http.get('/auth/') request
              $timeout(function() {
                authenticated = true
                $state.go(next,toParams)
              },1000)
            }
          })
        }
      ])
    </script>
  </body>
</html>

이 인증 차단을 수행하기 위해 사용해야 하는 다른 방법이 있습니까?저는 이 인증 차단이 클라이언트 측에서만 가능하다는 것을 알고 있습니다.이 예제에서는 서버 측면을 보여주지 않습니다.

$urlRouterProvider. 그렇지 않으면 $state에 $urlRouterProvider.("/foo)를 조합하여 사용할 때 이 버그가 ui-router로 표시됩니다.시작을 바꿉니다.

이슈 - https://github.com/angular-ui/ui-router/issues/600

Frank Wallis는 좋은 해결책을 제공합니다. 그렇지 않으면 함수를 인수로 사용하는 긴 형태의 방법을 사용합니다.

$urlRouterProvider.otherwise( function($injector, $location) {
            var $state = $injector.get("$state");
            $state.go("app.home");
        });

수고했어 프랭크!

가짜로.이것은 상호작용 문제입니다.$urlRouterProvider그리고.$stateProvider. 사용하면 안 됩니다.$urlRouterProvider나를 위하여otherwise. 나는 다음과 같은 것을 사용해야 합니다.

$stateProvider.state("otherwise", {
    url: "*path",
    template: "Invalid Location",
    controller: [
              '$timeout','$state',
      function($timeout,  $state ) {
        $timeout(function() {
          $state.go('/foo')
        },2000)
      }]
});

또는 투명한 방향 전환:

$stateProvider.state("otherwise", {
    url: "*path",
    template: "",
    controller: [
              '$state',
      function($state) {
        $state.go('/foo')
      }]
});

지금 모두:

<!doctype html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
  </head>
  <body ng-app="clientApp">
    <div ui-view="" ></div>

    <script>
      var app = angular.module('clientApp', ['ui.router'])

      var myRouteProvider = [
                '$stateProvider',
        function($stateProvider) { 

          $stateProvider.state('/foo', {
            url: '/foo',
            template: '<div>In Foo now</div>',
            reloadOnSearch: false
          })

          $stateProvider.state("otherwise", {
              url: "*path",
              template: "",
              controller: [
                        '$state',
                function($state) {
                  $state.go('/foo')
                }]
          });
        }]
      app.config(myRouteProvider)

      var authenticated = false
      app.run([
                 '$rootScope', '$log','$state','$timeout',
        function ($rootScope,   $log,  $state,  $timeout) {
          $rootScope.$on('$stateChangeStart', function (event, next, toParams) {
            if (!authenticated) {
              event.preventDefault()
              //following $timeout is emulating a backend $http.get('/auth/') request
              $timeout(function() {
                authenticated = true
                $state.go(next,toParams)
              },1000)
            }
          })
        }
      ])
    </script>
  </body>
</html>

저도 이런 문제가 있었습니다.아래는 각도 허가 프로젝트에서 영감을 얻은 해결해야 할 코드입니다.

주요 컨셉은 flag()를 추가하는 것입니다.$$finishAuthorize)를 수동으로 상태로 만들고, 이 플래그에 의해 무한 루프를 끊습니다.우리가 알아야 할 또 다른 점은{notify: false}옵션의$state.go, 방송을"$stateChangeSuccess"수동 이벤트

$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
    if (toState.$$finishAuthorize) {
        return;
    }
    if (!authenticated) {
        event.preventDefault();
        toState = angular.extend({'$$finishAuthorize': true}, toState);

        // following $timeout is emulating a backend $http.get('/auth/') request
        $timeout(function() {
            authenticated = true;
            $state.go(toState.name, toParams, {notify: false}).then(function() {
                $rootScope.$broadcast('$stateChangeSuccess', toState, toParams, fromState, fromParams);
            });
        },1000)
    }
);

저도 이런 문제가 있었습니다.https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-make-a-trailing-slash-optional-for-all-routes 에서 후행 슬래시를 선택 사항으로 만들 것을 제안한 것이 코드였던 것으로 드러났습니다.

$urlRouterProvider.rule(function ($injector, $location) {
  var path = $location.url();

  console.log(path);
  // check to see if the path already has a slash where it should be
  if (path[path.length - 1] === '/' || path.indexOf('/?') > -1) {
    return;
  }

  if (path.indexOf('?') > -1) {
    return path.replace('?', '/?');
  }

  return path + '/';
});

로 바꿨습니다.

$urlRouterProvider.rule(function ($injector, $location) {
  var path = $location.url();
  // check to see if the path already has a slash where it should be
  if (path[path.length - 1] === '/' || path.indexOf('/?') > -1) {
    return;
  }
  if (path.indexOf('?') > -1) {
    $location.replace().path(path.replace('?', '/?'));
  }
  $location.replace().path(path + '/');
});

새 경로를 반환하지 않고 교체만 해도 상태 변경 시작이 트리거되지 않습니다.

실행 블록을 다음과 같이 변경해 봅니다.

    app.run([
             '$rootScope', '$log','$state','$interval',
    function ($rootScope,   $log,  $state,  $interval) {
      var authenticated = false;
      $rootScope.$on('$stateChangeStart', function (event, next, toParams) {
        if (!authenticated) {
          event.preventDefault()
          //following $timeout is emulating a backend $http.get('/auth/') request
        }
      })


      var intervalCanceller = $interval(function() {
        //backend call
        if(call succeeds & user authenticated) {
          authenticated = true;
          $interval.cancel(intervalCanceller);
          $state.go(next, toParams);
        }
      }, 3000);
    }
  ])

저는 다양한 성공도를 가지고 위의 솔루션을 시도했습니다(Ionic cordova 애플리케이션을 구축하고 있습니다).어느 순간 저는 무한 루프를 얻지 못하고 상태가 바뀌지만, 저는 멍한 시야로 남게 되었습니다.추가했습니다.{ reload:true }도움이 될 것 같네요해봤습니다.{ notify:false }그리고.{ notify: true }그건 도움이 되지 않았습니다

는 결국 https://stackoverflow.com/a/26800804/409864 에서 나온 대부분의 답변을 사용하게 되었습니다.

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

  // Do not redirect if going to an error page
  if (toState.name === 'app.error') {
    return;
  }

  // Do not redirect if going to the login page
  if (toState.name === 'app.login') {
    return;
  }

  // Do not redirect if there is a token present in localstorage
  var authData = localstorage.getItem('auth');
  if (authData.token) {
    return;
  }

  // We do not have a token, are not going to the login or error pages, time to redirect!
  event.preventDefault();
  console.debug('No auth credentials in localstorage, redirecting to login page');
  $state.go('engineerApp.home', {}, {reload: true}); // Empty object is params
});

언급URL : https://stackoverflow.com/questions/25065699/why-does-angularjs-with-ui-router-keep-firing-the-statechangestart-event

반응형