programing

약속이 해결될 때까지 각의 항해를 중지하다

mailnote 2023. 3. 2. 22:25
반응형

약속이 해결될 때까지 각의 항해를 중지하다

레일 설계 타임아웃이 발생했을 때 발생하는 깜박임을 방지하고 싶지만 Angular는 리소스에서 다음 인증 오류가 발생할 때까지 알 수 없습니다.

템플릿이 렌더링되고 리소스에 대한 Ajax 호출이 발생하며 로그인하기 위한 레일 설계로 방향 수정됩니다.상태 변경 시마다 레일에 ping을 수행하여 레일 세션이 만료된 경우 템플릿이 렌더링되기 전에 즉시 리다이렉트합니다.

ui-router는 모든 루트에 적용할 수 있는 해상도를 가지고 있지만 전혀 DRY가 아닌 것 같습니다.

제가 가진 건 이거예요.그러나 그 약속은 이미 상태가 전환될 때까지 해결되지 않는다.

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
        //check that user is logged in
        $http.get('/api/ping').success(function(data){
          if (data.signed_in) {
            $scope.signedIn = true;
          } else {
            window.location.href = '/rails/devise/login_path'
          }
        })

    });

약속 결과에 따라 새 템플릿이 렌더링되기 전에 상태 전환을 중단하려면 어떻게 해야 합니까?

저는 이것이 경기에 매우 늦었다는 것을 알지만, 저는 제 의견을 밖으로 던지고 제가 생각하는 주 변화를 "일시 중지"할 수 있는 훌륭한 방법에 대해 논의하고 싶었습니다.angular-ui-router 문서에 따르면 약속인 상태의 "해결" 개체 구성원은 상태 로드가 완료되기 전에 해결되어야 합니다.따라서 기능적인 솔루션(아직 청소 및 완벽하지는 않지만)은 $state에 있는 "toState"의 해결 객체에 약속을 추가하는 것입니다.Change Start" :

예를 들어 다음과 같습니다.

$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
    toState.resolve.promise = [
        '$q',
        function($q) {
            var defer = $q.defer();
            $http.makeSomeAPICallOrWhatever().then(function (resp) {
                if(resp = thisOrThat) {
                    doSomeThingsHere();
                    defer.resolve();
                } else {
                    doOtherThingsHere();
                    defer.resolve();
                }
            });
            return defer.promise;
        }
    ]
});

이를 통해 API 콜이 종료되고 API로부터의 반환에 기초한 모든 결정이 이루어지는 약속에 대한 상태 변경이 확실하게 유지됩니다.새 페이지를 탐색하기 전에 서버 측에서 로그인 상태를 확인하기 위해 이 기능을 사용했습니다.API 호출이 해결되면 "event.proventDefault()"를 사용하여 원래 네비게이션을 중지하고 로그인 페이지로 라우팅하거나(if state.name != "displaced"로 코드 블록 전체를 표시함), 사용자가 바이패스 부란 및 preventDefault()를 사용하지 않고 단순히 지연된 약속을 해결하도록 허용합니다.

비록 원본 포스터가 그들의 문제를 오래 전에 알아냈다고 확신하지만, 나는 이것이 다른 누군가에게 도움이 되기를 진심으로 바란다.

편집

사람들을 호도하고 싶지 않다고 생각했어요.상태에 해결 개체가 있는지 확실하지 않은 경우 코드는 다음과 같습니다.

$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
    if (!toState.resolve) { toState.resolve = {} };
    toState.resolve.pauseStateChange = [
        '$q',
        function($q) {
            var defer = $q.defer();
            $http.makeSomeAPICallOrWhatever().then(function (resp) {
                if(resp = thisOrThat) {
                    doSomeThingsHere();
                    defer.resolve();
                } else {
                    doOtherThingsHere();
                    defer.resolve();
                }
            });
            return defer.promise;
        }
    ]
});

편집 2

해결 정의가 없는 상태에서 이 기능을 사용하려면 app.config에 이 기능을 추가해야 합니다.

   var $delegate = $stateProvider.state;
        $stateProvider.state = function(name, definition) {
            if (!definition.resolve) {
                definition.resolve = {};
            }

            return $delegate.apply(this, arguments);
        };

if (!toState.resolve) { toState.resolve = {} }; 것 instateChangeStart는 후 를 받지 않습니다.stateChangeStart는 해결 dict를

합니다.event.preventDefault()

주의: 이행을 방지하려면 event.proventDefault()를 사용합니다.

$scope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){ 
        event.preventDefault(); 
        // transitionTo() promise will be rejected with 
        // a 'transition prevented' error
})

아마 제가 사용하는 것은resolve@ responsented@charlietfl 로서 합니다.

편집:

그래서 스테이트 변경 이벤트에서 prevent Default()를 사용할 기회가 있었습니다.그것은 다음과 같습니다.

.run(function($rootScope,$state,$timeout) {

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

        // check if user is set
        if(!$rootScope.u_id && toState.name !== 'signin'){  
            event.preventDefault();

            // if not delayed you will get race conditions as $apply is in progress
            $timeout(function(){
                event.currentScope.$apply(function() {
                    $state.go("signin")
                });
            },300)
        } else {
            // do smth else
        }
    }
)

}

편집

최신 문서에는 사용자 사용 방법의 예가 포함되어 있습니다.sync()에 계속되다preventDefault호출되었지만 이 "", "예외", "예외", "예외", "예외"$locationChangeSuccess하지 않는 합니다.$stateChangeStart다음 예시와 같이 이벤트가 갱신된 문서에서 가져옵니다.

angular.module('app', ['ui.router'])
    .run(function($rootScope, $urlRouter) {
        $rootScope.$on('$stateChangeStart', function(evt) {
            // Halt state change from even starting
            evt.preventDefault();
            // Perform custom logic
            var meetsRequirement = ...
            // Continue with the update and state transition if logic allows
            if (meetsRequirement) $urlRouter.sync();
        });
    });

여기 이 문제에 대한 저의 해결책이 있습니다.이 방법은 잘 작동하며, 여기에 있는 다른 답변의 정신에 부합합니다.조금 치웠을 뿐이에요.무한 루프를 방지하기 위해 루트 스코프에 'stateChangeBypass'라는 커스텀 변수를 설정하고 있습니다.또한 상태가 로그인 상태인지 확인하고 로그인 상태일 경우 항상 허용됩니다.

function ($rootScope, $state, Auth) {

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

        if($rootScope.stateChangeBypass || toState.name === 'login') {
            $rootScope.stateChangeBypass = false;
            return;
        }

        event.preventDefault();

        Auth.getCurrentUser().then(function(user) {
            if (user) {
                $rootScope.stateChangeBypass = true;
                $state.go(toState, toParams);
            } else {
                $state.go('login');
            }
        });

    });
}

$urlRouter.sync()는 stateChangeStart와 함께 사용할 수 없기 때문에 다음과 같은 대체 방법이 있습니다.

    var bypass;
    $rootScope.$on('$stateChangeStart', function(event,toState,toParams) {
        if (bypass) return;
        event.preventDefault(); // Halt state change from even starting
        var meetsRequirement = ... // Perform custom logic
        if (meetsRequirement) {  // Continue with the update and state transition if logic allows
            bypass = true;  // bypass next call
            $state.go(toState, toParams); // Continue with the initial state change
        }
    });

기존 같은하여, 「이벤트 핸들러」를 .루트 스코프의 이벤트핸들러를 사용하여 리슨하고 있었습니다.$stateChangeStart제 허락 처리를 위해서요.불행히도 이것은 때때로 무한 다이제스트를 일으키는 끔찍한 부작용을 가져왔다(왜 내가 코드를 작성하지 않았는지 모르겠다).

제가 생각해낸 해결책은 다소 부족한 것이지만, 항상 이행을 막는 입니다.event.preventDefault()다음으로 사용자가 비동기 콜을 통해 로그인하고 있는지 여부를 판단합니다.한 후, 「」를 사용해 주세요.$state.go을 사용법 중요한 것은, 「」를 하는 입니다.notify$state.go이렇게 이 다른 상태시키는 것을 할 수 .$stateChangeStart.

 event.preventDefault();
 return authSvc.hasPermissionAsync(toState.data.permission)
    .then(function () {
      // notify: false prevents the event from being rebroadcast, this will prevent us
      // from having an infinite loop
      $state.go(toState, toParams, { notify: false });
    })
    .catch(function () {
      $state.go('login', {}, { notify: false });
    });

이 , 이것은 필요하게 됩니다.동기를 사용했을 경우hasPermission페이지에 대한 요청 시 권한이 로드되지 않았을 수 있습니다. : (아마도 ui-router에 문의할 수 있습니다.continueTransition어떤 방법이 있을까요?

authSvc.hasPermissionAsync(toState.data.permission).then(continueTransition).catch(function() {
  cancelTransition();
  return $state.go('login', {}, { notify: false });
});

on메서드 반환a deregistration function for this listener.

그러면 다음과 같은 작업을 수행할 수 있습니다.

var unbindStateChangeEvent = $scope.$on('$stateChangeStart', 
  function(event, toState, toParams) { 
    event.preventDefault(); 

    waitForSomething(function (everythingIsFine) {
      if(everythingIsFine) {
        unbindStateChangeEvent();
        $state.go(toState, toParams);
      }
    });
});

저는 The Ryberg가 제안한 솔루션을 매우 좋아합니다. 이상한 속임수 없이 한 곳에서 모든 작업을 수행할 수 있기 때문입니다.루트 스코프에서 stateChangeBypass를 필요로 하지 않도록 더욱 개선할 수 있는 방법이 있습니다.주된 생각은, 애플리케이션을 「실행」하기 전에 코드로 초기화해 두는 것입니다.그리고 초기화 여부만 기억하면 다음과 같이 할 수 있습니다.

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

    if (dataService.isInitialized()) {
        proceedAsUsual(); // Do the required checks and redirects here based on the data that you can expect ready from the dataService
    } 
    else {

        event.preventDefault();

        dataService.intialize().success(function () {
                $state.go(toState, toParams);
        });
    }
});

그러면 데이터가 이미 원하는 방식으로 초기화되어 있다는 것만 기억하면 됩니다. 예:

function dataService() {

    var initialized = false;

    return {
        initialize: initialize,
        isInitialized: isInitialized
    }

    function intialize() {

        return $http.get(...)
                    .success(function(response) {
                            initialized=true;
                    });

    }

    function isInitialized() {
        return initialized;
    }
};

$state에서 이행 파라미터를 취득할 수 있습니다.ChangeStart를 시작하여 서비스에 저장한 다음 로그인을 처리한 후 전환을 다시 시작합니다.또, 시큐러티가 서버로부터 http 401 에러로서 송신되고 있는 경우는, https://github.com/witoldsz/angular-http-auth 를 참조할 수도 있습니다.

나도 같은 문제에 부딪혔어 이걸 이용해서 해결했어

angular.module('app', ['ui.router']).run(function($rootScope, $state) {
    yourpromise.then(function(resolvedVal){
        $rootScope.$on('$stateChangeStart', function(event){
           if(!resolvedVal.allow){
               event.preventDefault();
               $state.go('unauthState');
           }
        })
    }).catch(function(){
        $rootScope.$on('$stateChangeStart', function(event){
           event.preventDefault();
           $state.go('unauthState');
           //DO Something ELSE
        })

    });
        var lastTransition = null;
        $rootScope.$on('$stateChangeStart',
            function(event, toState, toParams, fromState, fromParams, options)  {
                // state change listener will keep getting fired while waiting for promise so if detect another call to same transition then just return immediately
                if(lastTransition === toState.name) {
                    return;
                }

                lastTransition = toState.name;

                // Don't do transition until after promise resolved
                event.preventDefault();
                return executeFunctionThatReturnsPromise(fromParams, toParams).then(function(result) {
                    $state.go(toState,toParams,options);
                });
        });

stateChangeStart 중에 무한 루프를 회피하기 위해 부울가드를 사용하는 데 문제가 있었습니다.따라서 같은 이행이 다시 시도되었는지 확인하고 같은 이행이 시도되면 즉시 되돌리는 이 접근방식을 취했습니다.이 경우 약속은 아직 해결되지 않았기 때문입니다.

언급URL : https://stackoverflow.com/questions/20094273/stop-angular-ui-router-navigation-until-promise-is-resolved

반응형