AngularJS - ¿Cómo usar $ routeParams para generar templateUrl?

96

Nuestra aplicación tiene navegación de 2 niveles. Queremos usar AngularJS $routeProviderpara proporcionar dinámicamente plantillas a un <ng-view />. Estaba pensando en hacer algo como esto:

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

Simplemente no sé cómo poblar las partes dentro del <<>>. Sé que el primaryNav y el secundarioNav se vinculan a $ routeParams, pero ¿cómo accedo a $ routeParams aquí para servir dinámicamente la plantilla?

dnc253
fuente

Respuestas:

84

No pude encontrar una manera de inyectar y usar el $routeParamsservicio (que supongo que sería una mejor solución) Intenté esto pensando que podría funcionar:

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

Lo que produjo este error:

Proveedor desconocido: $ routeParams de myApp

Si algo así no es posible, puede cambiar su templateUrlpara apuntar a un archivo HTML parcial que acaba de tener ng-includey luego configurar la URL en su controlador usando $routeParams como este:

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

Con esto como tu urlRouter.html

<div ng-include src="templateUrl"></div>
Gloopy
fuente
7
El problema por el que el primero no funciona está documentado en groups.google.com/forum/?fromgroups=#!topic/angular/qNi5lqm-Ps8 . Como config()se pasan los objetivos de inyección solo a los proveedores, no a instancias de servicio reales como $routePrams.
2012
18
En realidad, no es necesario que cree el "archivo html de una línea"; solo use la clave "template:" en lugar de "templateUrl" y proporcione una cadena que contenga el html one-liner ;-)
DominikGuzei
1
¿No podrías usar en templatelugar de templateUrl?
Kaiser
1
Esto realmente funcionará, pero ¿qué pasa con la aplicación de un controlador para cada plantilla seleccionada? El uso de este método lo dejará con un solo controlador "maestro": "RouteController"
Yaniv Efraim
9
si se establece templatea una función, se puede pasar $routeParamsa esa función: $routeProvider.when('/:pNav/:sNav', { template: fn($routeParams) { return $routeParams.pNav + '/' + $routeParams.sNav + '.html' } });. Sin embargo, no puede definir dinámicamente un controlador de esta manera :(
jacob
131

Esta función muy útil ahora está disponible a partir de la versión 1.1.2 de AngularJS. Se considera inestable pero lo he usado (1.1.3) y funciona bien.

Básicamente, puede usar una función para generar una cadena templateUrl. A la función se le pasan los parámetros de ruta que puede usar para construir y devolver la cadena 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:'/'});
    }
);

Muchas gracias a https://github.com/lrlopez por la solicitud de extracción.

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

jlareau
fuente
5
Esto ahora es totalmente compatible con 1.2 y probablemente sea la mejor manera: docs.angularjs.org/api/ngRoute/provider/$routeProvider
Stu
¿Qué pasa con un controlador dinámico basado en los parámetros?
Oak
Por favor, por favor (¡por favor!) Dime que esto se puede hacer con controllers...?
Cody
¿Cómo se accede al controlador desde la plantilla en este caso (proporcionado por $ routeProvider)? Normalmente, si el controlador está vinculado por la directiva ng-controller = "myController", puede hacer referencia a myController como myCtrl. ¿Cómo defino myCtrl en este caso?
FlavorScape
@FlavorScape También tuve este problema - la solución es hacer algo como $ routeProvider.when ("/ foo", {controller: "FooController", controllerAs: "foo", templateUrl: "foo.html"});
Erin Drummond
18

templateUrl se puede utilizar como función para devolver la URL generada. Podemos manipular la URL con un argumento de paso que toma routeParams.

Vea el ejemplo.

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

Espero que esto ayude.

Ravi K.
fuente
7

Está bien, creo que lo tengo ...

Primero un poco de fondo: la razón por la que necesitaba esto era colocar Angular encima de Node Express y hacer que Jade procesara mis parciales por mí.

Así que esto es lo que tienes que hacer ... (¡bebe cerveza y pasa más de 20 horas en ella primero!) ...

Cuando configure su módulo, guarde $routeProviderglobalmente:

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

});
...

Eso puede ser más información de la que se necesitaba ...

  • Básicamente, querrá almacenar la $routeProvidervar de su módulo globalmente, por ejemplo, routeProviderpara que sus controladores puedan acceder a él.

  • Luego, puede usar routeProvidery crear una ruta NUEVA (no puede 'RESTABLECER una ruta' / 'REpromise'; debe crear una nueva), acabo de agregar una barra (/) al final para que sea tan semántica como el primero.

  • Luego (dentro de su controlador), configure templateUrlla vista a la que desea acceder.

  • Elimina la controllerpropiedad del .when()objeto, no sea que obtengas un bucle de solicitud infinito.

  • Y finalmente (aún dentro del controlador), use $location.path()para redirigir a la ruta que acaba de crear.

Si está interesado en cómo colocar una aplicación Angular en una aplicación Express, puede bifurcar mi repositorio aquí: https://github.com/cScarlson/isomorph .

Y este método también le permite mantener las vinculaciones de datos bidireccionales de AngularJS en caso de que desee vincular su HTML a su base de datos utilizando WebSockets: de lo contrario, sin este método, sus vinculaciones de datos angulares solo se generarán {{model.param}}.

Si clona esto en este momento, necesitará mongoDB en su máquina para ejecutarlo.

¡Espero que esto resuelva este problema!

Cody

No beba el agua de su baño.

Cody
fuente
3

Enrutador: -

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

Controlador:-

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

Creo que es una debilidad en angularjs que $ routeParams NO sea visible dentro del enrutador. Una pequeña mejora marcaría una gran diferencia durante la implementación.

Ron deBoer
fuente
3

He agregado soporte para esto en mi bifurcación de angular. Te permite especificar

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

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

No estoy seguro de que esto se recoja ya que es un poco contra el grano para angular, pero es útil para mí

Jamie Paté
fuente
¡Tocar el asunto exacto! No lo he usado todavía, pero REALMENTE lo necesito. ¿Hay alguna otra advertencia que deba tener en cuenta? Además, ¿alguna palabra sobre Angular implementándolo? - Me gusta usar el CDN.
Cody
No tengo idea, nunca conseguí firmar el papeleo, así que este es un callejón sin salida, pero puedes tomar el cambio e intentar conseguirlo tú mismo (ya no trabajo en la empresa con la que estaba cuando hice esto, y ellos no perseguir angularjs más)
Jamie Pate
Bien, gracias por la información y su contribución al problema. Lo sacaré y lo jugaré en un minuto.
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;
    });

en index.html

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

firstParam y secondParam pueden ser cualquier cosa según sus necesidades.

Aniket Jha
fuente
0

Tenía un problema similar y usé en $stateParamslugar derouteParam

mcneela86
fuente