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ですか?ください?

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


1
ui-routerでは、各州のURLを定義する必要はありません。URLを変更せずに州から州へ移動できます
Jonathan de M.

URL全体を更新しますか、それとも検索パスのみを更新しますか?私は、検索パスを更新する解決策を探して、ここでそれを上に発見された:stackoverflow.com/questions/21425378/...
フロリアン湖

@johnathan本当に?単一のURLのみを表示してそれを実行したいのですが$urlRouterProvider.otherwise、状態ではなくURLを操作しているようです。うーん、多分私は2つのURLを使用するか、それが無効なURLであることを示す他の方法を見つけることができます。
Mawgはモニカを2016

回答:


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 2014

25
私の場合、次のように機能しました。 $state.transitionTo('.detail', {id: newId}, { location: true, inherit: true, relative: $state.$current, notify: false }) 基本的に、notifyをfalseに、locationをtrueに設定します
Arjen de Vries 14年

6
@ArjendeVriesはい、期待どおりに動作していますが、予期しない動作が見つかりました。多くのtransitionToメソッド呼び出し(リロードなしで)をいじってから、最終的に新しい状態(つまり、url)に移動すると、古いコントローラーが再起動されます。
Premchandra Singh 2014

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

このメソッドは現在、オプションのパラメーターを備えた角度バージョンのuiルーターのマスターバージョンにのみ含まれていると思います(これもいいですね)。クローンしてソースからビルドする必要があります

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

}]);

これにより、いずれかのパラメータが欠落している場合でも、状態を解決できます。SEOは1つの目的であり、読みやすさは別の目的です。

上記の例では、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 2014

1
マスターからビルドしましたか?ソリューションを追加した時点で、オプションのパラメーターはソースから手動でビルドする必要があるバージョンにのみ含まれていたことに注意してください。これはv.0.3がリリースされるまでリリースに含まれません。
wiherek 2014

1
簡単なメモ。nateabeleのおかげで、オプションパラメータは数日前にリリースされたv0.2.11で使用できます。
rich97

これは非常に混乱します:$ urlRouterProvider.deferIntercept();の使用方法 コントローラをリロードせずにパラメータを更新できるように?これは実際にはそれを示していません。run関数内で、同期するかどうかを指定してifステートメントを評価できますが、操作する必要があるのは新旧のURLだけです。これがインスタンスの2つだけを使用してparamsを更新するだけであるインスタンスであることをどのように知ることができますか?ロジックはどうなりますか...(古い状態と新しい状態が同じである場合、コントローラをリロードしないでください?)私は混乱しています。
btm1 2015年

右、このユースケースはネストされた状態であったと思います、私は子の状態をリロードしたくなかったのでインターセプトしていました。今は、絶対的なターゲティングビューを使用してそれを行い、変化しないとわかっている状態のビューを定義するほうがいいと思います。とにかく、これはまだ良いです。完全な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
});

その他のソリューションは、ルートプロバイダーに関連しています。このソリューションは、私が$ stateProviderを使用していて$ routeProviderを使用していない場合のように機能します。
eeejay 2015年

@eeejay基本的に質問ui-routerのみが求められています。他のソリューションが機能していて$routerProvider、アーキテクチャがまったく異なる$routeProvider$stateProviderはどういうことですか?
Pankaj Parkar

これで[戻る]ボタンが機能しないようにするにはどうすればよいですか?つまり、バックプレスで、異なる
パラメーターを

このソリューションでは、ui-routerに
通知

2
私はこれを試しましたが、$onInit()を使用するたびにコンポーネントで呼び出されているようです$state.go。100%大丈夫ではないようです。
Carrm 2018年

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を更新するときにトレーニングコントローラが2回呼び出されない .../.../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

私はこれをずっと前にバージョンで実行しました: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
      },
      '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-routerは必要ないと思います。$ locationサービスで利用可能なドキュメントは、最初の段落で、「... $ locationへの変更はブラウザーのアドレスバーに反映される」と述べています。「ブラウザは、ブラウザのURLが変更されても、ページ全体が再読み込みされることはありません。」

それを念頭に置いて、(メソッドがゲッターとセッターの両方であるため)$ location.pathを次のようなものに変更しないでください。

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

ドキュメントのパスは常にスラッシュで始める必要があり、それが欠けている場合、これはそれを追加しますノート。


を使用しui-router、を使用する$location.path(URL_PATH)と、ページは自動的に再レン​​ダリングされますか?
Kousha 14

ええ、それは再レンダリングします。$ locationChangeStartでevent.preventDefault()を試してみましたが、どちらも機能しません。つまり、状態の再レンダリングが停止しますが、URLが更新されなくなります。
wiherek 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.