web-dev-qa-db-ja.com

AngularJS UIルーター - 状態を再ロードせずにURLを変更

現在私たちのプロジェクトはデフォルトの$routeProviderを使用しています、そして私はページをリロードせずにurlを変更するためにこの "hack"を使用しています:

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();

ネスティングルートのためにrouteProviderui-routerに置き換えることを考えていますが、これをui-routerに見つけることはできません。

それは可能ですか - angular-ui-routerでも同じようにしますか?

なぜこれが必要なのですか?例を挙げて説明しましょう。
新しいカテゴリを作成するためのルートは、SAVEでclickingの後に/category/newですsuccess-alertを表示し、ルート/category/new/caterogy/23に変更します(23 - dbに格納された新しいアイテムのIDです)

126
vuliad

単に$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}) 
153
rezKesh

さて、解決しました:) Angular UIルーターにこの新しいメソッドがあります、$ 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();
  }]);

私はこのメソッドは現在、masterバージョンのAngular ui router、オプションのパラメータを持つもの(これもいいですね、ところで)にしか含まれていないと思います。それはクローンを作成してソースからビルドする必要があります

grunt build

ドキュメントはソースからもアクセスできます。

grunt ngdocs

(/ siteディレクトリに組み込まれています)// README.MDの詳細情報

これを行うには、動的パラメータ(私はこれまで使ったことがない)を使う方法があります。 nateabeleにはたくさんのクレジットがあります。


補足として、Angular UIルーターの$ 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'
    });

}]);

それが何をするかというと、パラメータの1つが欠落していても、状態を解決することができます。 SEOは目的、読みやすさは別の目的です。

上記の例では、doorsSingleを必須パラメーターにしたいと思いました。それらを定義する方法は明確ではありません。ただし、複数のオプションパラメータを指定しても問題なく機能するため、実際には問題ありません。議論はここにあります https://github.com/angular-ui/ui-router/pull/1032#issuecomment-4919609

48
wiherek

この問題に多くの時間を費やした後、これが私が働いたことです

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

このセットアップは私にとって次の問題を解決しました:

  • URLを.../から.../123に更新するときに、トレーニングコントローラが2回呼び出されることはありません。
  • 別の状態に移動してもトレーニングコントローラーが再度呼び出されない

状態設定

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 ...
}   
7
martinoss

あなただけのURLを変更する必要があるが、状態の変更を防ぐ場合:

場所を変更します(履歴で置き換えたい場合は、.replaceを追加します)。

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

あなたの状態へのリダイレクトを防ぐ:

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

私はこれをやったが、ずっと前のバージョンで:UIルーターの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
      },
      '[email protected]': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
        controller: 'viewVoucherCtrl',
        reloadOnSearch: false
      },
      '[email protected]': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
        controller: 'voucherCtrl',
        reloadOnSearch: false
      }
    },
    reloadOnSearch: false
  })
2
sheelpriy

呼び出し

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

十分です。ニアト!

のドキュメントから

dynamictrueの場合、パラメータ値を変更しても状態は開始または終了しません。解決は再取得されず、ビューも再ロードされません。

[...]

これは、パラメータの値が変化したときにコンポーネントが自分自身を更新するUIを構築するのに役立ちます。

1
Moritz Ringler

このようなことを試してください

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