[angularjs] AngularJS UI 라우터-상태를 다시로드하지 않고 URL 변경

현재 우리 프로젝트는 default $routeProvider를 사용하고 있으며 url페이지를 다시로드하지 않고 변경하기 위해이 “해킹”을 사용하고 있습니다 .

services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
    $location.skipReload = function () {
        var lastRoute = $route.current;
        var un = $rootScope.$on('$locationChangeSuccess', function () {
            $route.current = lastRoute;
            un();
        });
        return $location;
    };
    return $location;
}]);

그리고 controller

$locationEx.skipReload().path("/category/" + $scope.model.id).replace();

내가 대체 생각하고 routeProvider함께 ui-router중첩 경로에 대한,하지만의를 찾을 수 없습니다 ui-router.

가능 angular-ui-router합니까?

왜 이것이 필요합니까? 내가 예와 함께 설명 보자
경로를 새로운 카테고리를 만드는 것은 /category/new
clickingSAVE I 쇼에 success-alert내가 경로 변경하려는 /category/new/caterogy/23(23 – DB에 저장된 새 항목의 ID입니다)



답변

간단히 $state.transitionTo 대신 사용할 수 있습니다 $state.go . 내부적으로 $state.go 호출 $state.transitionTo 하지만 옵션을 자동으로 설정합니다 { location: true, inherit: true, relative: $state.$current, notify: true } . 전화를 걸고 $state.transitionTo 설정할 수 있습니다 notify: false . 예를 들면 다음과 같습니다.

$state.go('.detail', {id: newId}) 

에 의해 대체 될 수있다

$state.transitionTo('.detail', {id: newId}, {
    location: true,
    inherit: true,
    relative: $state.$current,
    notify: false
})

편집 : fracz가 제안한대로 간단히 다음과 같습니다.

$state.go('.detail', {id: newId}, {notify: false}) 


답변

좋아, 해결 🙂 Angular UI Router에는이 새로운 메소드 $ urlRouterProvider.deferIntercept ()
https://github.com/angular-ui/ui-router/issues/64가 있습니다.

기본적으로 이것은 다음과 같습니다.

angular.module('myApp', [ui.router])
  .config(['$urlRouterProvider', function ($urlRouterProvider) {
    $urlRouterProvider.deferIntercept();
  }])
  // then define the interception
  .run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
    $rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
      // Prevent $urlRouter's default handler from firing
      e.preventDefault();

      /**
       * provide conditions on when to
       * sync change in $location.path() with state reload.
       * I use $location and $state as examples, but
       * You can do any logic
       * before syncing OR stop syncing all together.
       */

      if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
        // your stuff
        $urlRouter.sync();
      } else {
        // don't sync
      }
    });
    // Configures $urlRouter's listener *after* your custom listener
    $urlRouter.listen();
  }]);

이 방법은 현재 angular ui router 의 마스터 버전 (옵션 매개 변수가있는 btw) 에만 포함되어 있다고 생각합니다 . 소스를 사용하여 복제하고 빌드해야합니다.

grunt build

문서는 다음을 통해 소스에서도 액세스 할 수 있습니다.

grunt ngdocs

(/ site 디렉토리에 내장 됨) // README.MD의 추가 정보

동적 매개 변수 (사용하지 않은)에 의해 이것을 수행하는 다른 방법이있는 것 같습니다 . nateabele에 많은 크레딧.


참고로, 여기 에 Angular UI Router의 $ stateProvider의 선택적 매개 변수 가 있습니다.

angular.module('myApp').config(['$stateProvider', function ($stateProvider) {

  $stateProvider
    .state('main.doorsList', {
      url: 'doors',
      controller: DoorsListCtrl,
      resolve: DoorsListCtrl.resolve,
      templateUrl: '/modules/doors/doors-list.html'
    })
    .state('main.doorsSingle', {
      url: 'doors/:doorsSingle/:doorsDetail',
      params: {
        // as of today, it was unclear how to define a required parameter (more below)
        doorsSingle: {value: null},
        doorsDetail: {value: null}
      },
      controller: DoorsSingleCtrl,
      resolve: DoorsSingleCtrl.resolve,
      templateUrl: '/modules/doors/doors-single.html'
    });

}]);

그 중 하나는 매개 변수 중 하나가 누락 된 경우에도 상태를 해결할 수 있다는 것입니다. SEO는 한 가지 목적, 가독성입니다.

위의 예에서 doorsSingle이 필수 매개 변수가되기를 원했습니다. 그것들을 정의하는 방법은 명확하지 않습니다. 여러 선택적 매개 변수와 함께 작동하므로 실제로 문제가되지 않습니다. 토론은 여기 https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090


답변

이 문제와 함께 많은 시간을 보낸 후 여기에 내가 일한 것이 있습니다.

$state.go('stateName',params,{
    // prevent the events onStart and onSuccess from firing
    notify:false,
    // prevent reload of the current state
    reload:false,
    // replace the last record when changing the params so you don't hit the back button and get old params
    location:'replace',
    // inherit the current params on the url
    inherit:true
});


답변

부름

$state.go($state.current, {myParam: newValue}, {notify: false});

여전히 컨트롤러를 다시로드합니다.

이를 피하려면 매개 변수를 동적으로 선언해야합니다.

$stateProvider.state({
    name: 'myState',
    url: '/my_state?myParam',
    params: {
        myParam: {
          dynamic: true,
        }
    },
    ...
});

그런 다음 notify전화 가 필요하지 않습니다.

$state.go($state.current, {myParam: newValue})

충분하다. 니토!

로부터 문서 :

경우 dynamic이며 true, 상태가 종료 / 입력하게되지 파라미터 값을 변경한다. 리졸 브는 다시 가져 오지 않으며 뷰도 다시로드되지 않습니다.

[…]

이는 매개 변수 값이 변경 될 때 구성 요소가 자체적으로 업데이트되는 UI를 빌드하는 데 유용 할 수 있습니다.


답변

이 설정은 다음과 같은 문제를 해결했습니다.

  • 에서 URL을 업데이트 할 때 교육 컨트롤러를 두 번 호출되지 않습니다 .../.../123
  • 다른 상태로 탐색 할 때 훈련 컨트롤러가 다시 호출되지 않습니다

상태 구성

state('training', {
    abstract: true,
    url: '/training',
    templateUrl: 'partials/training.html',
    controller: 'TrainingController'
}).
state('training.edit', {
    url: '/:trainingId'
}).
state('training.new', {
    url: '/{trainingId}',
    // Optional Parameter
    params: {
        trainingId: null
    }
})

다른 컨트롤러에서 상태 호출

$scope.editTraining = function (training) {
    $state.go('training.edit', { trainingId: training.id });
};

$scope.newTraining = function () {
    $state.go('training.new', { });
};

훈련 컨트롤러

var newTraining;

if (!!!$state.params.trainingId) {

    // new      

    newTraining = // create new training ...

    // Update the URL without reloading the controller
    $state.go('training.edit',
        {
            trainingId : newTraining.id
        },
        {
            location: 'replace', //  update url and replace
            inherit: false,
            notify: false
        });

} else {

    // edit

    // load existing training ...
}   


답변

URL 만 변경해야하지만 변경 상태는 방지하십시오.

위치 변경 (기록에서 바꾸려면 .replace 추가) :

this.$location.path([Your path]).replace();

당신의 상태로 리디렉션을 방지 :

$transitions.onBefore({}, function($transition$) {
 if ($transition$.$to().name === '[state name]') {
   return false;
 }
});


답변

나는 이것을했지만 오래 전에 버전 : UI0.2의 v0.2.10과 같은 :

$stateProvider
  .state(
    'home', {
      url: '/home',
      views: {
        '': {
          templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
          controller: 'mainCtrl'
        },
      }
    })
  .state('home.login', {
    url: '/login',
    templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
    controller: 'authenticationCtrl'
  })
  .state('home.logout', {
    url: '/logout/:state',
    controller: 'authenticationCtrl'
  })
  .state('home.reservationChart', {
    url: '/reservations/?vw',
    views: {
      '': {
        templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
        controller: 'reservationChartCtrl',
        reloadOnSearch: false
      },
      'viewVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
        controller: 'viewVoucherCtrl',
        reloadOnSearch: false
      },
      'addEditVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
        controller: 'voucherCtrl',
        reloadOnSearch: false
      }
    },
    reloadOnSearch: false
  })