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


134

현재 우리 프로젝트는 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/newclickingSAVE I 쇼에 success-alert내가 경로 변경하려는 /category/new/caterogy/23(23 - DB에 저장된 새 항목의 ID입니다)


1
ui-router에서 각 주에 대한 URL을 정의 할 필요가 없습니다. URL을 변경하지 않고도 주에서 주를 탐색 할 수 있습니다.
Jonathan de M.

전체 URL 또는 검색 경로 만 업데이트 하시겠습니까? 검색 경로를 업데이트하는 솔루션을 찾고 있었고 여기에서 발견했습니다 : stackoverflow.com/questions/21425378/…
Florian Loch

@johnathan 정말요? 하나의 URL 만 표시하고 싶지만 $urlRouterProvider.otherwise상태가 아닌 URL에서 작동하는 것 같습니다. 흠, 어쩌면 나는 2 개의 URL을 사용하거나 유효하지 않은 URL임을 나타낼 수있는 다른 방법을 찾을 수 있습니다.
Mawg는 모니카 복원

답변:


164

간단히 $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}) 

16
"상태를 다시로드하지 않고 URL 변경"대신 "상태를 다시로드 할 때 URL 유지"가 아닙니까?
Peter Hedberg

25
나를 위해 그것은 다음과 일 : $state.transitionTo('.detail', {id: newId}, { location: true, inherit: true, relative: $state.$current, notify: false }) 그래서 참으로 잘못된 위치에 기본적으로 설정 통지
아르옌 드 브리스

6
@ArjendeVries 예 예상대로 작동하지만 예기치 않은 동작을 발견했습니다. 마지막으로 새로운 상태 (예 : url)로 이동할 때 많은 transitionTo 메소드 호출 (다시로드하지 않고)을 가지고 놀면 이전 컨트롤러를 다시 시작합니다.
Premchandra Singh

2
@ Premchandra Singh : 같은 문제가 있습니다. 상태를 벗어나면 기존 컨트롤러가 다시 초기화됩니다. wiherek에서 허용되는 솔루션과 동일한 문제가 발생합니다. 참조 여기 github.com/angular-ui/ui-router/issues/64
martinoss

15
더 간단합니다 : $state.go('.detail', {id: newId}, {notify: false}).
fracz

48

좋아, 해결 :) 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


선택적 매개 변수가 작동하지 않는 것 같습니다. Error: Both params and url specicified in state 'state'. 그것은 문서 에서 이것이 유효하지 않은 사용법 이라고 말합니다 . 조금 실망했다.
Rhys van der Waerden

1
당신은 마스터에서 구축 했습니까? 솔루션을 추가 한 시점에서 선택적 매개 변수는 소스에서 수동으로 빌드해야하는 버전에만 포함되었습니다. 이것은 v.0.3이 나올 때까지 릴리스에 포함되지 않습니다.
wiherek

1
간단한 메모입니다. nateabele 덕분에 며칠 전에 릴리스 된 v0.2.11에서 선택적 매개 변수를 사용할 수 있습니다.
rich97

이것은 매우 혼란 스럽습니다. $ urlRouterProvider.deferIntercept ()를 어떻게 사용합니까? 컨트롤러를 다시로드하지 않고 매개 변수를 업데이트 할 수 있습니까? 이것은 실제로 저를 보여주지 않습니다. 실행 기능 내에서 if 문을 동기화하거나 동기화하지 않도록 평가 할 수 있지만 작업해야 할 것은 이전 URL과 새 URL입니다. 이것이 내가하고 싶은 모든 작업을 위해 두 개의 URL로 매개 변수를 업데이트하는 것임을 어떻게 알 수 있습니까? 논리는 ....입니까 (이전 상태와 새 상태가 동일하면 컨트롤러를 다시로드하지 않습니까?) 혼란 스럽습니다.
btm1

맞습니다.이 유스 케이스는 중첩 된 상태에 있다고 생각합니다. 자식 상태를 다시로드하고 싶지 않았으므로 인터셉트했습니다. 이제는 절대 타겟팅보기를 사용하고 변경하지 않을 것으로 알려진 상태에서보기를 정의하면됩니다. 어쨌든, 이것은 여전히 ​​좋습니다. 전체 URL을 얻습니다. 즉, URL에서 상태를 추측 할 수 있습니다. 또한 쿼리 및 경로 매개 변수 등도 있습니다. 상태와 URL을 중심으로 앱을 만들면 정보가 많이 있습니다. 실행 블록에서 서비스 등에 액세스 할 수도 있습니다. 질문에 대한 대답이 있습니까?
wiherek

16

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

$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
});

다른 솔루션은 경로 공급자와 관련이 있습니다. 이 솔루션은 $ routeProvider를 사용하지 않고 $ stateProvider를 사용하는 경우와 같이 작동합니다.
eeejay

@eeejay 기본적으로 질문을 요청 된 ui-router경우에만 해당, 다른 솔루션을 위해 일하고 있었다 말할 수있는 방법 $routerProvider, $routeProvider$stateProvider건축 완전히 다른 ..
판 카즈 Parkar

뒤로 버튼이 작동하지 않게하려면 어떻게해야합니까? 내가 아닌 같은 다른 PARAMS을 가진 상태로 이전 상태 / URL을 다시 눌러 이동, 의미
gaurav5430

나는이 솔루션 브라우저 다시하여 거라 생각하지 작업, 우리는 그것을 알고를 말도없이 UI 라우터 상태를 변경하는로
판 카즈 Parkar

2
나는 이것을 시도했고를 $onInit()사용할 때마다 내 구성 요소에서 호출되는 것처럼 보입니다 $state.go. 나에게는 100 % 괜찮아 보이지 않습니다.
Carrm

8

부름

$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를 빌드하는 데 유용 할 수 있습니다.


7

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

  • 에서 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 ...
}   

비슷한 전략을 사용하려고했지만 컨트롤러가 편집 페이지에서 trainigId의 값을 얻지 못했습니다. URL에서 직접 ui-sref를 사용하여 편집 페이지에 액세스하려고했습니다. 내 코드는 정확히 당신과 같습니다.
Nikhil Bhandari

이것은 저에게
효과적이며

3

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

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

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

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

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

2

나는 이것을했지만 오래 전에 버전 : 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
  })

0

이런 식으로 해보십시오

$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})

-6

나는 이것을 위해 당신이 전혀 UI 라우터가 필요하지 않다고 생각합니다. $ location 서비스에 사용 가능한 설명서 는 첫 번째 단락에서 "... $ location에 대한 변경 사항은 브라우저 주소 표시 줄에 반영됩니다."라고 말합니다. 나중에 "무엇을하지 않습니까? 브라우저 URL이 변경 될 때 전체 페이지를 다시로드하지 않습니다."라고 계속 말합니다.

따라서이를 염두에두고 다음과 같은 방법으로 $ location.path (메소드가 getter 및 setter이므로)를 간단하게 변경하십시오.

var newPath = IdFromService;
$location.path(newPath);

문서 노트 경로는 항상 슬래시로 시작해야하지만 누락 된 경우이 추가됩니다.


내가 사용하는 경우 ui-router, 사용을 $location.path(URL_PATH)자동으로 페이지가-이 렌더링 다시!
Kousha

예, 다시 렌더링합니다. $ locationChangeStart에서 event.preventDefault ()를 사용해 보았습니다. 작동하지 않습니다. 즉 상태가 다시 렌더링되지 않지만 URL이 업데이트되지 않습니다.
wiherek
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.