AngularJS dinamik yönlendirme


88

Şu anda yerleşik yönlendirme içeren bir AngularJS uygulamam var. Çalışıyor ve her şey yolunda.

App.js dosyam şöyle görünüyor:

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

Uygulamamda, / pages dizini içinde yeni html dosyalarını kopyalayıp ekleyebileceğiniz yerleşik bir CMS var .

Dinamik olarak eklenen yeni dosyalar için bile yine de yönlendirme sağlayıcısından geçmek istiyorum.

İdeal bir dünyada yönlendirme modeli şöyle olacaktır:

$ routeProvider.when ('/ sayfaadı ', { şablonUrl : '/ sayfalar / sayfaadı .html', denetleyici: CMSController});

Yeni sayfa adım "contact.html" ise "/ contact" yi açısal olarak alıp "/pages/contact.html" adresine yönlendirmek isterim.

Bu mümkün mü ?! ve eğer öyleyse nasıl ?!

Güncelleme

Şimdi bunu yönlendirme yapılandırmamda bulabilirsiniz:

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

ve CMSController'ımda:

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

Bu, geçerli templateUrl değerini doğru değere ayarlar.

Ancak şimdi ng-görünümünü yeni templateUrl değeri ile değiştirmek istiyorum . Bu nasıl başarılır?

Yanıtlar:


133
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'
        });
    }
]);
  • * Eklenmesi , dinamik olarak birden çok dizin düzeyiyle çalışmanıza olanak tanır. Örnek: / page / cars / sell / list bu sağlayıcıda yakalanacak

Dokümanlardan (1.3.0):

"TemplateUrl bir işlevse, aşağıdaki parametrelerle çağrılacaktır:

{Dizi.} - geçerli rotayı uygulayarak geçerli $ location.path () öğesinden çıkarılan rota parametreleri "

Ayrıca

ne zaman (yol, rota): Yöntem

  • yol, iki nokta üst üste ile başlayan ve bir yıldız ile biten adlandırılmış grupları içerebilir: örneğin: isim *. Rota eşleştiğinde tüm karakterler hevesle verilen isim altında $ routeParams içinde saklanır.

5
Zamanla birlikte hareket etmemiz gerekiyor ... v1.0.2'de eksik olan oluşturduğum işlevsellik artık mevcut. Buna kabul edilen cevabı güncelleme
Greg

Dürüst olmak gerekirse, bunu şimdiki 1.3 beta ile hiç çalıştırmadım
Archimedes Trajano

Aslında bunu yaptığımda işe yaradı ... ne zaman ('/: page', {templateUrl: function (parametreler) {return parameters.page + '.html';}
Archimedes Trajano

Cidden .. Angular'ın bunu varsayılan bir davranış olarak görmemesi gerçekten aptalca ... Bu manuel yönlendirme çok saçma
Guilherme Ferreira

3
Lütfen açıklayınız, Nereden urlattrayarlanır veya gönderilir, yani ne urlattr.nameüretecek?
Sami

37

Tamam çözdüm.

Çözüm GitHub'a eklendi - http://gregorypratt.github.com/AngularDynamicRouting

App.js yönlendirme yapılandırmamda:

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

Sonra CMS denetleyicimde:

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'];

# Görüntülemeler benim <div id="views" ng-view></div>

Artık standart yönlendirme ve dinamik yönlendirme ile çalışıyor.

Test etmek için about.html dosyasını portfolyo.html olarak kopyaladım, bazı içeriğini değiştirdim ve /#/pages/portfoliotarayıcıma girdim ve hey presto portfolyo.html görüntülendi ....

Güncelleme Eklendi $ uygulamak ve bu dinamik içerik böylece html $ derleme enjekte edilebilir.


2
Bu, doğru anladığım takdirde yalnızca statik içerikle çalışır. Bunun nedeni, denetleyiciyi jQuery aracılığıyla (angular kapsamı dışında) oluşturduktan sonra DOM'u değiştiriyor olmanızdır. {{This}} gibi değişkenler işe yarayabilir (denemek zorunda kalacağım) ancak yönergeler büyük olasılıkla çalışmayacaktır. Şu anda işe yarayabileceği için dikkatli olun, ancak kodu daha sonra kırabilir ..
Tiago Roldão

Doğru, ciltleme benim için işe yaramıyor, ancak istemcilerin yalnızca yeni sayfalar ekleyebilmesini istediğim için fazla telaşlanmıyorum. Eklediğim herhangi bir sayfa, rota yapılandırması aracılığıyla uygun şekilde belirtirim. Yine de iyi bir nokta.
Greg

1
Statik html içeriği oluşturmak istiyorsanız bu kötü bir çözüm değildir. Aklınızda bulundurduğunuz sürece, temelde ng-görünümünü statik (açısal olmayan) içerikle geçersiz kılıyorsunuz. Bunu akılda tutarak, ikisini ayırmak, bir <div id = "user-views"> </div> öğesi gibi bir şey oluşturmak ve oraya "kullanıcı şablonunuzu" enjekte etmek daha temiz olacaktır. Ayrıca, $ route.current.templateUrl'yi geçersiz kılmanın - bir $ kapsam.userTemplate modeli oluşturmanın ve $ ('# kullanıcı görünümleri ") yapmanın kesinlikle bir anlamı yoktur. Load ($ kapsam.userTemplate) daha temizdir ve açısalların hiçbirini bozmaz kod.
Tiago Roldão

1
Hayır - ng-view direktifi oldukça sınırlıdır - veya daha iyisi, yerel yönlendirme sistemi ile kullanım için spesifiktir (bu da yine de sınırlı, imho). İçeriği bir DOM öğesine enjekte ederek, açısal yapının yeniden okunmasını söylemek için $ compile yöntemini çağırarak söylediğiniz gibi yapabilirsiniz. Bu, yapılması gereken herhangi bir bağlamayı tetikleyecektir.
Tiago Roldão

2
Çalışır, ancak denetleyicinizde DOM manipülasyonu yapmamalısınız.
dmackerman

16

Bence böyle bir şeyi yapmanın en kolay yolu rotaları daha sonra çözmek, rotaları örneğin json üzerinden sorabilirsiniz. Yapılandırma aşamasında, $ allow aracılığıyla $ routeProvider'dan bir fabrika yaptığımı kontrol edin, böylece çalışma aşamasında ve hatta denetleyicilerde bile $ routeProvider nesnesini kullanmaya devam edebilirim.

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

Aliasing $routeProviderbir şekilde kullanmak için factory(mevcut sonrasÖ configgüvenlik ve uygulama uyum ile iyi oynamak olmaz) - (! Upvote) her iki şekilde, serin tekniği.
Cody

@Cody güvenlik / uygulama uyum notunu açıklayabilir misiniz? Benzer bir teknedeyiz ve yukarıdaki cevap gibi bir şey gerçekten kullanışlı olacaktır.
virtualandy

2
@virtualandy, bir sağlayıcıyı farklı aşamalarda kullanıma sunduğunuz için bu genellikle harika bir yaklaşım değildir - bu da yapılandırma aşamasında gizlenmesi gereken yüksek seviyeli araçları sızdırabilir. Benim önerim UI-Router kullanmak (birçok zorluğun üstesinden gelir), "resol", "controllerAs" ve templateUrl'yi bir işleve ayarlamak gibi diğer fakülteleri kullanmaktır. Ayrıca, bir rota şemasının (şablon, şablonUrl, denetleyici, vb.) Herhangi bir bölümünü $ enterpolasyon yapabilen paylaşabileceğim bir "önceden çözme" modülü oluşturdum. Yukarıdaki çözüm daha zariftir - ama asıl endişeleriniz nelerdir?
Cody

1
@virtualandy, işte lazyLoaded şablonlar, denetleyiciler, vb. için bir modül - özür dileriz, bir depoda değil, ama işte bir keman: jsfiddle.net/cCarlson/zdm6gpnb ... URL parametrelerine göre. Modül biraz iş kullanabilir, ancak en azından bir başlangıç ​​noktasıdır.
Cody

@Cody - sorun değil, örnek ve daha fazla açıklama için teşekkürler. Mantıklı. Bizim durumumuzda, açısal rota segmenti kullanıyoruz ve güzel bir şekilde çalıştı. Ancak artık "dinamik" rotaları desteklememiz gerekiyor (bazı dağıtımlar sayfanın tüm özelliklerine / yollarına sahip olmayabilir veya adlarını değiştirebilir vb.) Ve aslında uygulamadan önce rotaları tanımlayan bazı JSON'da yükleme fikri bizim düşüncemizdi ama açıkça .config () içinde $ http / $ sağlayıcılarını kullanırken sorunlarla karşılaştı.
virtualandy

7

$ RouteProvider URI desenlerinde, aşağıdaki gibi değişken parametreler belirtebilirsiniz: $routeProvider.when('/page/:pageNumber' ... ve $ routeParams aracılığıyla denetleyicinizde buna erişebilirsiniz.

$ Route sayfasının sonunda güzel bir örnek var: http://docs.angularjs.org/api/ng.$route

DÜZENLEME (düzenlenen soru için):

Yönlendirme sistemi maalesef çok sınırlıdır - bu konuda çok sayıda tartışma vardır ve bazı çözümler önerilmiştir, yani birden çok adlandırılmış görünüm oluşturma vb. Ancak şu anda, ngView yönergesi her rota için yalnızca BİR görünüm sunmaktadır. bire bir temel. Bunu birden çok şekilde yapabilirsiniz - daha basit olanı, görünümün şablonunu içinde bir <ng-include src="myTemplateUrl"></ng-include>etiket bulunan bir yükleyici olarak kullanmaktır (denetleyicide $ kapsam.myTemplateUrl oluşturulur).

Daha karmaşık (ancak daha büyük ve daha karmaşık sorunlar için daha temiz) bir çözüm kullanıyorum, temelde $ route hizmetini tamamen atlayarak burada ayrıntılı olarak açıklanmıştır:

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


ng-includeYöntemi seviyorum . Gerçekten basit ve bu, DOM'u değiştirmekten çok daha iyi bir yaklaşım.
Neel

5

Bunun neden çalıştığından emin değilim, ancak dinamik (veya isterseniz joker karakter) rotalar açısal 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" kısmi yükler

example.com/bar-> "bar" kısmını kısmen yükler

Ng görünümünde herhangi bir ayarlamaya gerek yoktur. '/: A' durumu bulduğum tek değişkendir ve bunu başaracak .. '/: foo', tüm parçalarınız foo1, foo2 vb. Olmadıkça çalışmaz ... '/: a' herhangi bir kısmi ile çalışır isim.

Tüm değerler dinamik denetleyiciyi çalıştırır - dolayısıyla "aksi" yoktur, ancak dinamik veya joker karakter yönlendirme senaryosunda aradığınız şeyin bu olduğunu düşünüyorum ..


2

AngularJS 1.1.3'ten itibaren, artık yeni tümünü yakala parametresini kullanarak tam olarak istediğinizi yapabilirsiniz.

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

İşlemden:

Bu, routeProvider'ın iki nokta üst üste yerine yıldız işareti varsa, eğik çizgi içerse bile alt dizelerle eşleşen parametreleri kabul etmesini sağlar. Örneğin, gibi rotalar bunun gibi bir edit/color/:color/largecode/*largecode şeyle eşleşecektir http://appdomain.com/edit/color/brown/largecode/code/with/slashs.

Kendim test ettim (1.1.5 kullanarak) ve harika çalışıyor. Her yeni URL'nin denetleyicinizi yeniden yükleyeceğini unutmayın, bu nedenle herhangi bir durumu korumak için özel bir hizmet kullanmanız gerekebilir.


0

İşte iyi çalışan başka bir çözüm.

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

    }

})();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.