AngularJS - Como usar $ routeParams na geração do templateUrl?

96

Nosso aplicativo possui navegação em 2 níveis. Queremos usar o AngularJS $routeProviderpara fornecer modelos dinamicamente para um <ng-view />. Eu estava pensando em fazer algo parecido com isto:

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

Só não sei como preencher as partes dentro do <<>>. Eu sei que o primaryNav e o secondaryNav são vinculados aos $ routeParams, mas como faço para acessar $ routeParams aqui para servir dinamicamente o modelo?

dnc253
fonte

Respostas:

84

Não consegui encontrar uma maneira de injetar e usar o $routeParamsserviço (o que eu presumiria que seria uma solução melhor), tentei fazer isso pensando que poderia funcionar:

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

O que gerou este erro:

Provedor desconhecido: $ routeParams de myApp

Se algo assim não for possível, você pode mudar seu templateUrlpara apontar para um arquivo HTML parcial que acabou de ter ng-includee, em seguida, definir a URL em seu 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';
    }

Com isso como seu urlRouter.html

<div ng-include src="templateUrl"></div>
Gloopy
fonte
7
O problema de por que o primeiro não funciona está documentado em groups.google.com/forum/?fromgroups=#!topic/angular/qNi5lqm-Ps8 . Como alvos de injeção config()apenas para provedores são passados, não instâncias de serviço reais, como $routePrams.
nre
18
Na verdade, você não precisa criar o "arquivo html de uma linha" - apenas use a chave "template:" em vez de "templateUrl" e forneça uma string contendo o html de uma linha ;-)
DominikGuzei
1
Você não poderia simplesmente usar em templatevez de templateUrl?
kaiser,
1
Isso realmente funcionará, mas que tal aplicar um controlador para cada modelo selecionado? Usar este método deixará você com apenas um controlador "mestre": "RouteController"
Yaniv Efraim
9
se você definir templatepara uma função, você pode passar $routeParamspara essa função: $routeProvider.when('/:pNav/:sNav', { template: fn($routeParams) { return $routeParams.pNav + '/' + $routeParams.sNav + '.html' } });. No entanto, você não pode definir dinamicamente um controlador desta forma :(
jacob
131

Este recurso muito útil agora está disponível a partir da versão 1.1.2 do AngularJS. É considerado instável, mas eu usei (1.1.3) e funciona bem.

Basicamente, você pode usar uma função para gerar uma string templateUrl. A função recebe os parâmetros de rota que você pode usar para construir e retornar a string 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:'/'});
    }
);

Muito obrigado a https://github.com/lrlopez pela solicitação de pull.

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

Jlareau
fonte
5
Isso agora é totalmente suportado no 1.2 e é provavelmente a melhor maneira: docs.angularjs.org/api/ngRoute/provider/$routeProvider
Stu
que tal um controlador dinâmico baseado nos parâmetros?
Oak,
Por favor, por favor (por favor!) Diga-me que isso é possível fazer com controllers...?
Cody
como você acessa o controlador a partir do modelo neste caso (fornecido por $ routeProvider)? Normalmente, se o controlador é limitado pela diretiva ng-controller = "myController", você pode referenciá-lo a myController como myCtrl. Como posso definir myCtrl neste caso?
FlavorScape
@FlavorScape Eu também tive esse problema - a solução é fazer algo como $ routeProvider.when ("/ foo", {controller: "FooController", controllerAs: "foo", templateUrl: "foo.html"});
Erin Drummond
18

templateUrl pode ser usado como função com retorno de URL gerado. Podemos manipular o url com a passagem do argumento que leva routeParams.

Veja o exemplo.

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

Espero essa ajuda.

Ravi K.
fonte
7

Tudo bem, acho que entendi ...

Um pequeno histórico primeiro: O motivo pelo qual eu precisava disso era colocar o Angular no topo do Node Express e fazer com que Jade processasse meus parciais para mim.

Então aqui está o que você tem que fazer ... (beber cerveja e passar mais de 20 horas nela primeiro !!!) ...

Ao configurar seu módulo, salve $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/');

});
...

Isso pode ser mais informações do que o necessário ...

  • Basicamente, você vai querer armazenar a $routeProvidervar do seu módulo globalmente, por exemplo, de routeProviderforma que possa ser acessada por seus controladores.

  • Então você pode apenas usar routeProvidere criar uma NOVA rota (você não pode 'RESET a rota' / 'REpromise'; você deve criar uma nova), eu apenas adicionei uma barra (/) no final para que seja tão semântica como o primeiro.

  • Em seguida, (dentro do seu controlador), defina o templateUrlpara a visualização que deseja atingir.

  • Retire a controllerpropriedade do .when()objeto, para não obter um loop infinito de solicitação.

  • E por último (ainda dentro do Controller), use $location.path()para redirecionar para a rota que acabou de ser criada.

Se você estiver interessado em como inserir um aplicativo Angular em um aplicativo Express, pode fazer um fork do meu repo aqui: https://github.com/cScarlson/isomorph .

E este método também permite que você mantenha as ligações de dados bidirecionais do AngularJS no caso de desejar vincular seu HTML ao seu banco de dados usando WebSockets: caso contrário, sem este método, suas ligações de dados angulares serão apenas impressas {{model.param}}.

Se você clonar isso neste momento, precisará do mongoDB em sua máquina para executá-lo.

Espero que isso resolva o problema!

Cody

Não beba a água do banho.

Cody
fonte
3

Roteador:-

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

Acredito que seja um ponto fraco do angularjs que $ routeParams NÃO seja visível dentro do roteador. Um pequeno aprimoramento faria uma grande diferença durante a implementação.

Ron deBoer
fonte
3

Eu adicionei suporte para isso no meu fork do angular. Permite que você especifique

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

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

não tenho certeza se isso vai ser detectado, pois é meio contra a corrente para angular, mas é útil para mim

Jamie Pate
fonte
Pode apostar! Ainda não o usei, mas MUITO preciso. Há alguma outra advertência com a qual devo estar atento? Além disso, alguma palavra sobre a implementação do Angular? - Gosto de usar o CDN.
Cody
Não tenho ideia, nunca consegui assinar a papelada, então isso é um beco sem saída, mas você pode pegar o troco e tentar puxá-lo sozinho (eu não trabalho mais na empresa em que estava quando fiz isso, e eles não perseguir angularjs mais longe)
Jamie Pate
Ok, obrigado pela informação e sua contribuição para o problema - irei puxar e brincar com isso em um 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;
    });

em index.html

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

firstParam e secondParam podem ser qualquer coisa de acordo com suas necessidades.

Aniket Jha
fonte
0

Eu estava tendo um problema semelhante e usei em $stateParamsvez derouteParam

Mcneela86
fonte