AngularJS動的ルーティング


88

私は現在、ルーティングが組み込まれたAngularJSアプリケーションを持っています。これは機能し、すべて問題ありません。

私のapp.jsファイルは次のようになります。

angular.module('myapp', ['myapp.filters', 'myapp.services', 'myapp.directives']).
  config(['$routeProvider', function ($routeProvider) {
      $routeProvider.when('/', { templateUrl: '/pages/home.html', controller: HomeController });
      $routeProvider.when('/about', { templateUrl: '/pages/about.html', controller: AboutController });
      $routeProvider.when('/privacy', { templateUrl: '/pages/privacy.html', controller: AboutController });
      $routeProvider.when('/terms', { templateUrl: '/pages/terms.html', controller: AboutController });
      $routeProvider.otherwise({ redirectTo: '/' });
  }]);

私のアプリにはCMSが組み込まれており、新しいHTMLファイルを/ pagesディレクトリにコピーして追加できます。

新しい動的に追加されたファイルでも、ルーティングプロバイダーを通過したいと思います。

理想的な世界では、ルーティングパターンは次のようになります。

$ routeProvider.when( '/ ページ名 '、{templateUrl: '/ページ/ ページ名の.html'、コントローラ:CMSController})。

新しいページ名が「contact.html」の場合、angularで「/ contact」を取得して「/pages/contact.html」にリダイレクトします。

これも可能ですか?もしそうならどうですか?!

更新

これが私のルーティング設定にあります:

$routeProvider.when('/page/:name', { templateUrl: '/pages/home.html', controller: CMSController })

そして私のCMSControllerで:

function CMSController($scope, $route, $routeParams) {
    $route.current.templateUrl = '/pages/' + $routeParams.name + ".html";
    alert($route.current.templateUrl);
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];

これにより、現在のtemplateUrlが適切な値に設定されます。

ただしng-viewを新しいtemplateUrl値で変更したいと思います。これはどのように達成されますか?

回答:


132
angular.module('myapp', ['myapp.filters', 'myapp.services', 'myapp.directives']).
        config(['$routeProvider', function($routeProvider) {
        $routeProvider.when('/page/:name*', {
            templateUrl: function(urlattr){
                return '/pages/' + urlattr.name + '.html';
            },
            controller: 'CMSController'
        });
    }
]);
  • 追加*すると、複数レベルのディレクトリを動的に操作できます。例:/ page / cars / selling / listはこのプロバイダーでキャッチされます

ドキュメント(1.3.0)から:

「templateUrlが関数の場合、次のパラメーターで呼び出されます。

{Array。}-現在のルートを適用して現在の$ location.path()から抽出されたルートパラメータ

また

when(path、route):メソッド

  • パスには、コロンで始まり、スターで終わる名前付きグループを含めることができます(eg:name *)。ルートが一致すると、すべての文字が所定の名前で$ routeParamsに熱心に格納されます。

5
時代とともに動く必要がある...私が構築したv1.0.2で欠けていた機能が利用可能になりました。これに対する承認された回答の更新
グレッグ

正直に言うと、現在の1.3ベータ版でこれを機能させることはありませんでした
Archimedes Trajano 2014

実際にこれを実行すると機能しました... when( '/:page'、{templateUrl:function(parameters){return parameters.page + '.html';}
Archimedes Trajano

真剣に.. Angularがデフォルトの動作としてそれを持たないのは本当に愚かです...その手動ルーティングはばかげています
ギルヘルム・フェレイラ

3
説明してください、どこからurlattr設定または送信されurlattr.nameますか?つまり、何が生成されるのですか?
Sami

37

解決しました。

GitHubにソリューションを追加しました-http : //gregorypratt.github.com/AngularDynamicRouting

私のapp.jsルーティング設定:

$routeProvider.when('/pages/:name', {
    templateUrl: '/pages/home.html', 
    controller: CMSController 
});

次に、私のCMSコントローラーで:

function CMSController($scope, $route, $routeParams) {

    $route.current.templateUrl = '/pages/' + $routeParams.name + ".html";

    $.get($route.current.templateUrl, function (data) {
        $scope.$apply(function () {
            $('#views').html($compile(data)($scope));
        });
    });
    ...
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];

#viewsが私の <div id="views" ng-view></div>

したがって、これは標準ルーティングと動的ルーティングで機能します。

それをテストするために、portfolio.htmlと呼ばれるabout.htmlをコピーし、そのコンテンツの一部を変更/#/pages/portfolioし、ブラウザーに入力すると、prestoポートフォリオhtmlが表示されました。

更新 を追加しました$が適用され、$その動的なコンテンツを注入することができるように、HTMLにコンパイルします。


2
私が正しく理解していれば、これは静的コンテンツでのみ機能します。これは、jQueryを介して(angularのスコープ外で)コントローラーをインスタンス化した後にDOMを変更するためです。{{this}}のような変数は機能する可能性がありますが(私はそれを試さなければなりません)、ディレクティブはおそらく機能しません。...それは今便利なように、本を警戒するが、その後のコードを破ることができる
ティアゴRoldão

確かに、バインディングは機能しません。しかし、私はクライアントに新しいページを追加できるようにしたいだけなので、それほど面倒ではありません。追加するページはすべて、ルート構成を介して適切に指定します。良い点ですが。
グレッグ

1
静的なHTMLコンテンツをレンダリングしたい場合は、悪い解決策ではありません。あなたが心に留めている限り、あなたは本質的に静的な(非角度の)コンテンツでng-viewを上書きしています。これを念頭に置いて、2つを分離し、<div id = "user-views"> </ div>要素のようなものを作成し、そこに「ユーザーテンプレート」を挿入する方がきれいです。また、$ route.current.templateUrlをオーバーライドしてもまったく意味がありません-$ scope.userTemplateモデルを作成して$( '#user-views ")。load($ scope.userTemplate)を実行する方がきれいで、角度の角度を壊しませんコード
TiagoRoldão12年

1
いいえ-ng-viewディレクティブはかなり制限されています-または、より適切に言えば、ネイティブルーティングシステム(つまり、まだ制限されているimho)での使用に固有です。あなたが言ったように、コンテンツをDOM要素に注入してから、$ compileメソッドを呼び出して、angularに構造を再度読み取るように指示できます。これにより、実行する必要のあるバインディングがトリガーされます。
TiagoRoldão12年

2
動作しますが、コントローラーでDOM操作を行うべきではありません。
dmackerman 2013年

16

そのようなことをする最も簡単な方法は、後でルートを解決することだと思います。たとえば、jsonを介してルートを尋ねることができます。$ provideを使用して、構成フェーズ中に$ routeProviderからファクトリーを作成することを確認してください。これにより、実行フェーズで、さらにはコントローラーでも$ routeProviderオブジェクトを使用し続けることができます。

'use strict';

angular.module('myapp', []).config(function($provide, $routeProvider) {
    $provide.factory('$routeProvider', function () {
        return $routeProvider;
    });
}).run(function($routeProvider, $http) {
    $routeProvider.when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl'
    }).otherwise({
        redirectTo: '/'
    });

    $http.get('/dynamic-routes.json').success(function(data) {
        $routeProvider.when('/', {
            templateUrl: 'views/main.html',
            controller: 'MainCtrl'
        });
        // you might need to call $route.reload() if the route changed
        $route.reload();
    });
});

$routeProviderとして使用するエイリアスfactory(の後で利用可能config)は、セキュリティとアプリの凝集性をうまく発揮しません-どちらにしても、クールなテクニック(賛成です!)
コーディ

@Codyは、セキュリティ/アプリの結合メモを説明できますか?私たちは同じような船に乗っていて、上記の答えのようなものが本当に便利でしょう。
virtualandy 2014年

2
@virtualandy、プロバイダーをさまざまなフェーズで利用できるようにするため、一般的には優れたアプローチではありません。構成フェーズ内に隠す必要のある高レベルのユーティリティをリークする可能性があります。私の提案は、UI-Router(多くの困難を処理します)を採用し、「resolve」、「controllerAs」、およびtemplateUrlを関数に設定するような他の機能を使用することです。また、ルートスキームの任意の部分(template、templateUrl、controllerなど)を$ interpolateできる共有可能な「presolve」モジュールも作成しました。上記の解決策はよりエレガントな解決策ですが、あなたの主な懸念は何ですか?
Cody

1
@virtualandy、これはlazyLoadedテンプレート、コントローラーなどのモジュールです-リポジトリにはありませんが、ここにフィドルがあります:jsfiddle.net/cCarlson/zdm6gpnb ...このlazyLoadsは上記-そして-何でも補間できますURLパラメータに基づきます。モジュールはいくつかの作業を使用できますが、それは少なくとも出発点です。
コーディ

@Cody-問題ありません。サンプルと詳細な説明に感謝します。理にかなっている。この例では、angular-route-segmentを使用しており、うまく機能しています。しかし、「動的」ルート(一部のデプロイはページの完全な機能/ルートを持たない場合や、名前を変更する場合があるなど)と、実際に実装する前にルートを定義するJSONにロードするという概念をサポートする必要がありますしかし、明らかに.config()内で$ http / $ providersを使用すると問題が発生しました。
virtualandy 2014年

7

$ routeProvider URIパターンで、次のように変数パラメーターを指定し、$routeProvider.when('/page/:pageNumber' ...$ routeParamsを介してコントローラーでアクセスできます。

$ routeページの最後に良い例があります:http : //docs.angularjs.org/api/ng.$ro​​ute

編集(編集された質問用):

ルーティングシステムは残念ながら非常に制限されています。このトピックについては多くの議論があり、いくつかの解決策が提案されています。つまり、複数の名前付きビューを作成するなどです。しかし、現在、ngViewディレクティブはルートごとに1つのビューしか提供しません。 1対1ベースです。これには複数の方法で<ng-include src="myTemplateUrl"></ng-include>対処できます。最も簡単な方法は、ビューのテンプレートをローダーとして使用し、その中にタグを付けます($ scope.myTemplateUrlはコントローラーで作成されます)。

私はより複雑な(しかし、より大きくより複雑な問題に対してはよりクリーンな)ソリューションを使用し、基本的に$ routeサービスを完全にスキップします。

http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm


私はそのng-include方法が大好きです。本当にシンプルで、DOMを操作するよりもはるかに優れたアプローチです。
Neel、2014年

5

これが機能する理由はわかりませんが、動的な(または、必要に応じてワイルドカード)ルートが1.2.0-rc.2の角度で可能です...

http://code.angularjs.org/1.2.0-rc.2/angular.min.js
http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js

angular.module('yadda', [
  'ngRoute'
]).

config(function ($routeProvider, $locationProvider) {
  $routeProvider.
    when('/:a', {
  template: '<div ng-include="templateUrl">Loading...</div>',
  controller: 'DynamicController'
}).


controller('DynamicController', function ($scope, $routeParams) {
console.log($routeParams);
$scope.templateUrl = 'partials/' + $routeParams.a;
}).

example.com/foo-> "foo"パーシャルを読み込みます

example.com/bar->は "bar"パーシャルを読み込みます

ng-viewを調整する必要はありません。'/:a'ケースは、これを実現する唯一の変数です。 '/:foo'は、パーシャルがすべてfoo1、foo2などでない限り機能しません... '/:a'はどのパーシャルでも機能します名前。

すべての値が動的コントローラーを起動します。「それ以外の場合」はありませんが、動的またはワイルドカードルーティングシナリオで探しているものだと思います。


2

AngularJS 1.1.3以降では、新しいcatch-allパラメーターを使用して、希望どおりの操作を実行できます。

https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5

コミットから:

これにより、コロンの代わりにアスタリスクが前に付いている場合、スラッシュが含まれている場合でも、routeProviderはサブストリングと一致するパラメーターを受け入れることができます。たとえば、のようなルートedit/color/:color/largecode/*largecode はこのようなものと一致します http://appdomain.com/edit/color/brown/largecode/code/with/slashs

私はそれを自分でテストしました(1.1.5を使用)。新しいURLごとにコントローラーがリロードされるので、どのような状態でも維持するには、カスタムサービスを使用する必要があることに注意してください。


0

これは、うまく機能する別のソリューションです。

(function() {
    'use strict';

    angular.module('cms').config(route);
    route.$inject = ['$routeProvider'];

    function route($routeProvider) {

        $routeProvider
            .when('/:section', {
                templateUrl: buildPath
            })
            .when('/:section/:page', {
                templateUrl: buildPath
            })
            .when('/:section/:page/:task', {
                templateUrl: buildPath
            });



    }

    function buildPath(path) {

        var layout = 'layout';

        angular.forEach(path, function(value) {

            value = value.charAt(0).toUpperCase() + value.substring(1);
            layout += value;

        });

        layout += '.tpl';

        return 'client/app/layouts/' + layout;

    }

})();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.