AngularJS - Jak wykorzystać $ routeParams do generowania templateUrl?

96

Nasza aplikacja posiada 2 poziomy nawigacji. Chcemy używać AngularJS $routeProviderdo dynamicznego dostarczania szablonów do pliku <ng-view />. Myślałem o zrobieniu czegoś podobnego do tego:

angular.module('myApp', []).
config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/:primaryNav/:secondaryNav', {
        templateUrl: 'resources/angular/templates/nav/'+<<primaryNavHere>>+'/'+<<secondaryNavHere>>+'.html'
    });
}]);

Po prostu nie wiem, jak wypełnić części w <<>>. Wiem, że primaryNav i secondNav są powiązane z $ routeParams, ale jak uzyskać dostęp do $ routeParams tutaj, aby dynamicznie udostępniać szablon?

dnc253
źródło

Odpowiedzi:

84

Nie mogłem znaleźć sposobu na wstrzyknięcie i użycie $routeParamsusługi (co, jak zakładam, byłoby lepszym rozwiązaniem). Spróbowałem tego, myśląc, że może zadziałać:

angular.module('myApp', []).
    config(function ($routeProvider, $routeParams) {
        $routeProvider.when('/:primaryNav/:secondaryNav', {
            templateUrl: 'resources/angular/templates/nav/'+$routeParams.primaryNav+'/'+$routeParams.secondaryNav+'.html'
        });
    });

Co spowodowało ten błąd:

Nieznany dostawca: $ routeParams z myApp

Jeśli coś takiego nie jest możliwe, możesz zmienić swój, templateUrlaby wskazywał na częściowy plik HTML, który właśnie ma, ng-includea następnie ustawić adres URL w kontrolerze za pomocą $routeParamtakich znaków:

angular.module('myApp', []).
    config(function ($routeProvider) {
        $routeProvider.when('/:primaryNav/:secondaryNav', {
            templateUrl: 'resources/angular/templates/nav/urlRouter.html',
            controller: 'RouteController'
        });
    });

function RouteController($scope, $routeParams) {
        $scope.templateUrl = 'resources/angular/templates/nav/'+$routeParams.primaryNav+'/'+$routeParams.secondaryNav+'.html';
    }

Z tym jako twój urlRouter.html

<div ng-include src="templateUrl"></div>
Gloopy
źródło
7
Problem, dlaczego ten pierwszy nie działa, jest udokumentowany groups.google.com/forum/?fromgroups=#!topic/angular/qNi5lqm-Ps8 . Ponieważ cele iniekcji config()są przekazywane tylko do dostawców, a nie rzeczywiste wystąpienia usługi, takie jak $routePrams.
nre
18
Właściwie nie musisz tworzyć "jednowierszowego pliku html" - po prostu użyj klucza "template:" zamiast "templateUrl" i podaj do niego ciąg znaków zawierający
jednowierszowy
1
Nie mógłbyś po prostu użyć templatezamiast templateUrl?
kaiser
1
To faktycznie zadziała, ale co z zastosowaniem kontrolera dla każdego wybranego szablonu? Użycie tej metody pozostawi tylko jeden kontroler „główny”: „RouteController”
Yaniv Efraim,
9
jeśli ustawisz templatedo funkcji, można przejść $routeParamsdo tej funkcji: $routeProvider.when('/:pNav/:sNav', { template: fn($routeParams) { return $routeParams.pNav + '/' + $routeParams.sNav + '.html' } });. Nie możesz jednak dynamicznie zdefiniować kontrolera w ten sposób :(
jacob
131

Ta bardzo pomocna funkcja jest teraz dostępna począwszy od wersji 1.1.2 AngularJS. Jest uważany za niestabilny, ale używałem go (1.1.3) i działa dobrze.

Zasadniczo możesz użyć funkcji do wygenerowania ciągu templateUrl. Do funkcji przekazywane są parametry trasy, których można użyć do zbudowania i zwrócenia ciągu templateUrl.

var app = angular.module('app',[]);

app.config(
    function($routeProvider) {
        $routeProvider.
            when('/', {templateUrl:'/home'}).
            when('/users/:user_id', 
                {   
                    controller:UserView, 
                    templateUrl: function(params){ return '/users/view/' + params.user_id; }
                }
            ).
            otherwise({redirectTo:'/'});
    }
);

Dziękujemy https://github.com/lrlopez za pull request.

https://github.com/angular/angular.js/pull/1524

jlareau
źródło
5
Jest to teraz w pełni obsługiwane w wersji 1.2 i prawdopodobnie jest to najlepszy sposób: docs.angularjs.org/api/ngRoute/provider/$routeProvider
Stu
A co z dynamicznym kontrolerem opartym na parametrach?
Dąb,
Proszę, proszę (proszę!) Powiedz mi, że można to zrobić z controllers...?
Cody
jak w tym przypadku uzyskasz dostęp do kontrolera z szablonu (dostarczonego przez $ routeProvider)? Zwykle, jeśli kontroler jest powiązany przez dyrektywę ng-controller = "myController", możesz odwołać się do niego myController jako myCtrl. Jak zdefiniować myCtrl w tym przypadku?
FlavorScape
@FlavorScape Właśnie miałem ten problem - rozwiązaniem jest zrobienie czegoś takiego jak $ routeProvider.when ("/ foo", {kontroler: "FooController", controllerAs: "foo", templateUrl: "foo.html"});
Erin Drummond
18

Szablon templateUrl może służyć jako funkcja zwracająca wygenerowany adres URL. Możemy manipulować url przekazując argument, który przyjmuje routeParams.

Zobacz przykład.

.when('/:screenName/list',{
    templateUrl: function(params){
         return params.screenName +'/listUI'
    }
})

Mam nadzieję, że to pomoże.

Ravi K.
źródło
7

W porządku, myślę, że to rozumiem ...

Najpierw małe tło: potrzebowałem tego, aby przykleić Angular na wierzchu Node Express i poprosić Jade o przetworzenie za mnie moich stron.

Więc oto co muszę zrobić ... (najpierw pij piwo i spędź na nim ponad 20 godzin !!!) ...

Podczas konfigurowania modułu zapisz $routeProviderglobalnie:

// app.js:
var routeProvider
    , app = angular.module('Isomorph', ['ngResource']).config(function($routeProvider){

        routeProvider = $routeProvider;
        $routeProvider
            .when('/', {templateUrl: '/login', controller: 'AppCtrl'})
            .when('/home', {templateUrl: '/', controller: 'AppCtrl'})
            .when('/login', {templateUrl: '/login', controller: 'AppCtrl'})
            .when('/SAMPLE', {templateUrl: '/SAMPLE', controller: 'SAMPLECtrl'})
            .when('/map', {templateUrl: '/map', controller: 'MapCtrl'})
            .when('/chat', {templateUrl: '/chat', controller: 'ChatCtrl'})
            .when('/blog', {templateUrl: '/blog', controller: 'BlogCtrl'})
            .when('/files', {templateUrl: '/files', controller: 'FilesCtrl'})
            .when('/tasks', {templateUrl: '/tasks', controller: 'TasksCtrl'})
            .when('/tasks/new', {templateUrl: '/tasks/new', controller: 'NewTaskCtrl'})
            .when('/tasks/:id', {templateUrl: '/tasks', controller: 'ViewTaskCtrl'})
            .when('/tasks/:id/edit', {templateUrl: '/tasks', controller: 'EditTaskCtrl'})
            .when('/tasks/:id/delete', {templateUrl: '/tasks', controller: 'DeleteTaskCtrl'})
        .otherwise({redirectTo: '/login'});

});

// ctrls.js
...
app.controller('EditTaskCtrl', function($scope, $routeParams, $location, $http){

    var idParam = $routeParams.id;
    routeProvider.when('/tasks/:id/edit/', {templateUrl: '/tasks/' + idParam + '/edit'});
    $location.path('/tasks/' + idParam + '/edit/');

});
...

To może być więcej informacji, niż było potrzebne ...

  • Zasadniczo będziesz chciał przechowywać zmienne swojego modułu $routeProviderglobalnie, np. routeProviderTak, aby były dostępne dla twoich kontrolerów.

  • Następnie możesz po prostu użyć routeProvideri utworzyć NOWĄ trasę (nie możesz 'ZRESETOWAĆ trasy' / 'REpromise'; musisz utworzyć nową), po prostu dodałem ukośnik (/) na końcu, aby była tak semantyczna jako pierwszy.

  • Następnie (wewnątrz kontrolera) ustaw templateUrlwidok, w który chcesz trafić.

  • Usuń controllerwłaściwość .when()obiektu, aby nie uzyskać nieskończonej pętli żądań.

  • I na koniec (nadal w kontrolerze) użyj, $location.path()aby przekierować do właśnie utworzonej trasy.

Jeśli interesuje Cię, jak włożyć aplikację Angular do aplikacji Express, możesz rozwidlić moje repozytorium tutaj: https://github.com/cScarlson/isomorph .

Ta metoda pozwala również zachować dwukierunkowe powiązania danych AngularJS na wypadek, gdybyś chciał powiązać swój kod HTML z bazą danych za pomocą WebSockets: w przeciwnym razie bez tej metody twoje wiązania danych Angular będą po prostu wyprowadzane {{model.param}}.

Jeśli sklonujesz to teraz, będziesz potrzebować mongoDB na swoim komputerze, aby go uruchomić.

Mam nadzieję, że to rozwiązuje ten problem!

Cody

Nie pij swojej kąpieli.

Cody
źródło
3

Router: -

...
.when('/enquiry/:page', {
    template: '<div ng-include src="templateUrl" onload="onLoad()"></div>',
    controller: 'enquiryCtrl'
})
...

Kontroler:-

...
// template onload event
$scope.onLoad = function() {
    console.log('onLoad()');
    f_tcalInit();  // or other onload stuff
}

// initialize
$scope.templateUrl = 'ci_index.php/adminctrl/enquiry/'+$routeParams.page;
...

Uważam, że wadą angularjs jest to, że $ routeParams NIE jest widoczna wewnątrz routera. Drobne ulepszenie spowodowałoby ogromną różnicę podczas wdrażania.

Ron deBoer
źródło
3

Dodałem obsługę tego w moim rozwidleniu kątowym. Pozwala określić

$routeProvider
    .when('/:some/:param/:filled/:url', {
          templateUrl:'/:some/:param/:filled/template.ng.html'
     });

https://github.com/jamie-pate/angular.js/commit/dc9be174af2f6e8d55b798209dfb9235f390b934

nie jestem pewien, czy to zostanie podniesione, ponieważ jest trochę pod kątem dla kątów, ale jest dla mnie przydatne

Jamie Pate
źródło
Tak jest! Havent jeszcze go używał, ale NAPRAWDĘ go potrzebuję. Czy są jakieś inne zastrzeżenia, na które powinienem uważać? Jakieś wieści o implementacji Angulara? - Lubię korzystać z CDN.
Cody
Nie mam pojęcia, nigdy nie podpisałem dokumentów, więc to ślepy zaułek, ale możesz wziąć zmianę i spróbować ją wciągnąć (nie pracuję już w firmie, w której byłem, kiedy to robiłem, a oni nie ścigać angularjs dalej)
Jamie Pate
Ok, dzięki za informację i twój wkład w problem - wyciągnę to i pobawię się za minutę.
Cody
1
//module dependent on ngRoute  
 var app=angular.module("myApp",['ngRoute']);
    //spa-Route Config file
    app.config(function($routeProvider,$locationProvider){
          $locationProvider.hashPrefix('');
          $routeProvider
            .when('/',{template:'HOME'})
            .when('/about/:paramOne/:paramTwo',{template:'ABOUT',controller:'aboutCtrl'})
            .otherwise({template:'Not Found'});
    }
   //aboutUs controller 
    app.controller('aboutCtrl',function($routeParams){
          $scope.paramOnePrint=$routeParams.paramOne;
          $scope.paramTwoPrint=$routeParams.paramTwo;
    });

w index.html

<a ng-href="#/about/firstParam/secondParam">About</a>

firstParam i secondParam mogą być dowolne w zależności od potrzeb.

Aniket Jha
źródło
0

Miałem podobny problem i $stateParamszamiastrouteParam

mcneela86
źródło