AngularJS - Comment utiliser $ routeParams pour générer le templateUrl?

96

Notre application dispose de 2 niveaux de navigation. Nous voulons utiliser AngularJS $routeProviderpour fournir dynamiquement des modèles à un fichier <ng-view />. Je pensais faire quelque chose du genre:

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

Je ne sais tout simplement pas comment remplir les parties dans le fichier <<>>. Je sais que primaryNav et secondaryNav sont liés à $ routeParams, mais comment accéder à $ routeParams ici afin de servir dynamiquement le modèle?

dnc253
la source

Réponses:

84

Je n'ai pas pu trouver un moyen d'injecter et d'utiliser le $routeParamsservice (ce qui, je suppose, serait une meilleure solution), j'ai essayé ceci en pensant que cela pourrait fonctionner:

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

Ce qui a donné cette erreur:

Fournisseur inconnu: $ routeParams de myApp

Si quelque chose comme ça n'est pas possible, vous pouvez changer votre templateUrlpointeur vers un fichier HTML partiel qui vient de le contenir ng-include, puis définir l'URL dans votre contrôleur en utilisant des $routeParams comme ceci:

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

Avec ceci comme votre urlRouter.html

<div ng-include src="templateUrl"></div>
Gloopy
la source
7
Le problème pour lequel le premier ne fonctionne pas est documenté sur groups.google.com/forum/?fromgroups=#!topic/angular/qNi5lqm-Ps8 . Lorsque les cibles d'injection config()sont transmises uniquement aux fournisseurs, pas aux instances de service réelles telles que $routePrams.
nre
18
En fait, vous n'avez pas besoin de créer le "fichier html d'une ligne" - utilisez simplement la clé "template:" au lieu de "templateUrl" et fournissez-lui une chaîne contenant le html one-liner ;-)
DominikGuzei
1
Ne pourriez-vous pas simplement utiliser à la templateplace de templateUrl?
kaiser le
1
Cela fonctionnera réellement, mais qu'en est-il de l'application d'un contrôleur pour chaque modèle sélectionné? L'utilisation de cette méthode vous laissera avec un seul contrôleur "maître": "RouteController"
Yaniv Efraim
9
si vous définissez templateune fonction, vous pouvez passer $routeParamsdans cette fonction: $routeProvider.when('/:pNav/:sNav', { template: fn($routeParams) { return $routeParams.pNav + '/' + $routeParams.sNav + '.html' } });. Cependant, vous ne pouvez pas définir dynamiquement un contrôleur de cette façon :(
Jacob
131

Cette fonctionnalité très utile est désormais disponible à partir de la version 1.1.2 d'AngularJS. Il est considéré comme instable mais je l'ai utilisé (1.1.3) et cela fonctionne très bien.

En gros, vous pouvez utiliser une fonction pour générer une chaîne templateUrl. La fonction reçoit les paramètres d'itinéraire que vous pouvez utiliser pour générer et renvoyer la chaîne 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:'/'});
    }
);

Un grand merci à https://github.com/lrlopez pour la pull request.

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

Jlareau
la source
5
Ceci est maintenant entièrement pris en charge dans la version 1.2 et c'est probablement le meilleur moyen: docs.angularjs.org/api/ngRoute/provider/$routeProvider
Stu
qu'en est-il d'un contrôleur dynamique basé sur les paramètres?
Oak
S'il vous plaît, dites-moi (s'il vous plaît!) Qu'il est possible de faire avec controllers...?
Cody
comment accéder au contrôleur à partir du modèle dans ce cas (fourni par $ routeProvider)? Normalement, si le contrôleur est lié par la directive ng-controller = "myController", vous pouvez le référencer myController comme myCtrl. Comment définir myCtrl dans ce cas?
FlavorScape
@FlavorScape J'ai aussi eu ce problème - la solution est de faire quelque chose comme $ routeProvider.when ("/ foo", {controller: "FooController", controllerAs: "foo", templateUrl: "foo.html"});
Erin Drummond
18

templateUrl peut être utilisé comme fonction avec le renvoi de l'URL générée. Nous pouvons manipuler l'url avec un argument passant qui prend routeParams.

Voir l'exemple.

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

J'espère que cette aide.

Ravi K.
la source
7

Très bien, je pense que je l'ai compris ...

Petit rappel en premier: la raison pour laquelle j'en avais besoin était de coller Angular sur Node Express et de laisser Jade traiter mes partiels pour moi.

Alors, voici ce que je dois faire ... (boire de la bière et passer plus de 20 heures dessus en premier !!!) ...

Lorsque vous configurez votre module, enregistrez $routeProviderglobalement:

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

});
...

Cela peut être plus d'informations que ce qui était nécessaire ...

  • Fondamentalement, vous voudrez stocker $routeProviderglobalement la variable de votre module , par exemple routeProviderpour qu'elle soit accessible par vos contrôleurs.

  • Ensuite, vous pouvez simplement utiliser routeProvideret créer une NOUVELLE route (vous ne pouvez pas 'RESET a route' / 'REpromise'; vous devez en créer une nouvelle), j'ai juste ajouté une barre oblique (/) à la fin pour qu'elle soit aussi sémantique Comme le premier.

  • Puis (à l'intérieur de votre contrôleur), réglez le templateUrlsur la vue que vous souhaitez atteindre.

  • Supprimez la controllerpropriété de l' .when()objet, de peur d'obtenir une boucle de requête infinie.

  • Et enfin (toujours à l'intérieur du Controller), utilisez $location.path()pour rediriger vers la route qui vient d'être créée.

Si vous souhaitez savoir comment appliquer une application Angular à une application Express, vous pouvez créer mon dépôt ici: https://github.com/cScarlson/isomorph .

Et cette méthode vous permet également de conserver les liaisons de données bidirectionnelles AngularJS au cas où vous voudriez lier votre HTML à votre base de données à l'aide de WebSockets: sinon, sans cette méthode, vos liaisons de données angulaires ne sortiront que {{model.param}}.

Si vous le clonez à ce moment, vous aurez besoin de mongoDB sur votre machine pour l'exécuter.

J'espère que cela résout ce problème!

Cody

Ne buvez pas votre eau de bain.

Cody
la source
3

Routeur: -

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

Manette:-

...
// 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;
...

Je crois que c'est une faiblesse dans angularjs que $ routeParams ne soit PAS visible à l'intérieur du routeur. Une petite amélioration ferait toute la différence pendant la mise en œuvre.

Ron deBoer
la source
3

J'ai ajouté un support pour cela dans mon fork de angular. Il vous permet de spécifier

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

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

Je ne suis pas sûr que cela soit repris car il est un peu à contre-courant pour angulaire, mais cela m'est utile

Jamie Pate
la source
Droit dessus! Je ne l'ai pas encore utilisé mais en a vraiment besoin. Y a-t-il d'autres mises en garde auxquelles je devrais faire attention? Aussi, un mot sur Angular l'implémentant? - J'aime utiliser le CDN.
Cody
Aucune idée, je n'ai jamais fait signer les documents, donc c'est une impasse, mais vous pouvez prendre le changement et essayer de le faire vous-même (je ne travaille plus dans l'entreprise avec laquelle j'étais quand j'ai fait ça, et ils ne l'ont pas fait) poursuivre angularjs plus loin)
Jamie Pate
Ok, merci pour l'information et votre contribution au problème - je vais tirer ça et jouer avec ça dans une minute.
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;
    });

dans index.html

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

firstParam et secondParam peuvent être n'importe quoi selon vos besoins.

Aniket Jha
la source
0

J'avais un problème similaire et utilisé à la $stateParamsplace derouteParam

mcneela86
la source