Roteamento dynamic AngularJS

Eu atualmente tenho um aplicativo AngularJS com roteamento embutido. Ele funciona e está tudo bem.

Meu arquivo app.js é assim:

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

Meu aplicativo tem um CMS embutido onde você pode copiar e adicionar novos arquivos html dentro do diretório / pages .

Eu ainda gostaria de passar pelo provedor de roteamento, mesmo para os novos arquivos dinamicamente adicionados.

Em um mundo ideal, o padrão de roteamento seria:

$ routeProvider.when (‘/ pagename ‘, {templateUrl: ‘/ pages / pagename .html’, controller: CMSController});

Então, se o nome da minha nova página for “contact.html”, eu gostaria que o angular selecionasse “/ contato” e redirecionasse para “/pages/contact.html”.

Isso é possível ?! e se sim como ?!

Atualizar

Agora tenho isso na minha configuração de roteamento:

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

e no meu CMSController:

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

Isso define o templateUrl atual como o valor correto.

No entanto , gostaria de alterar a ng-view com o novo valor templateUrl. Como isso é feito?

 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' }); } ]); 
  • Adicionar * permite trabalhar com vários níveis de diretórios dinamicamente. Exemplo: / page / cars / selling / list será capturado nesse provedor

Dos docs (1.3.0):

“Se templateUrl for uma function, ela será chamada com os seguintes parâmetros:

{Array.} – parâmetros de rota extraídos do $ location.path () atual, aplicando a rota atual ”

Além disso

quando (caminho, rota): método

  • O caminho pode conter grupos nomeados começando com dois pontos e terminando com uma estrela: por exemplo: nome *. Todos os personagens são ansiosamente armazenados em $ routeParams sob o nome dado quando a rota coincide.

Ok resolvido isso.

Adicionada a solução ao GitHubhttp://gregorypratt.github.com/AngularDynamicRouting

Na minha configuração de roteamento app.js:

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

Então no meu controlador CMS:

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

Com #views sendo minhas

Então, agora funciona com roteamento padrão e roteamento dynamic.

Para testá-lo eu copiei about.html chamado de portfolio.html, mudei alguns de seus conteúdos e entrei em /#/pages/portfolio no meu navegador e hey presto portfolio.html foi exibido ….

Atualizado Adicionado $ apply e $ compile ao html para que o conteúdo dynamic possa ser injetado.

Acho que a maneira mais fácil de fazer isso é resolver as rotas mais tarde, você poderia pedir as rotas via json, por exemplo. Verifique que eu faço uma fábrica a partir do $ routeProvider durante a fase de configuração, via $ provide, para que eu possa continuar usando o object $ routeProvider na fase de execução e até mesmo nos controladores.

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

Nos padrões de URI $ routeProvider, você pode especificar parâmetros variables, como: $routeProvider.when('/page/:pageNumber' ... , e acessá-lo no seu controlador via $ routeParams.

Há um bom exemplo no final da página $ route: http://docs.angularjs.org/api/ng.$route

EDITAR (para a questão editada):

O sistema de roteamento é, infelizmente, muito limitado – há muita discussão sobre este tópico, e algumas soluções foram propostas, nomeadamente através da criação de múltiplas visões nomeadas, etc. Mas agora, a diretiva ngView serve apenas UMA visão por rota, em uma base um-para-um. Você pode fazer isso de várias maneiras – a mais simples seria usar o modelo da view como um carregador, com uma tag ($ scope.myTemplateUrl ser criado no controlador).

Eu uso uma solução mais complexa (mas mais limpa, para problemas maiores e mais complicados), basicamente ignorando completamente o serviço $ route, que é detalhado aqui:

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

Não sei por que isso funciona, mas rotas dinâmicas (ou curinga, se você preferir) são possíveis no formato 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: '
Loading...
', controller: 'DynamicController' }). controller('DynamicController', function ($scope, $routeParams) { console.log($routeParams); $scope.templateUrl = 'partials/' + $routeParams.a; }).

example.com/foo -> carrega “foo” parcial

example.com/bar-> carrega “bar” parcial

Não há necessidade de nenhum ajuste na visão geral. O caso ‘/: a’ é a única variável que encontrei que conseguirá isto .. ‘/: foo’ não funciona a menos que suas parciais sejam todas foo1, foo2, etc … ‘/: a’ funciona com qualquer parcial nome.

Todos os valores triggersm o controlador dynamic – portanto, não há “caso contrário”, mas acho que é o que você está procurando em um cenário de roteamento dynamic ou curinga.

A partir do AngularJS 1.1.3, agora você pode fazer exatamente o que você quer usando o novo parâmetro catch-all.

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

Do commit:

Isso permite que routeProvider aceite parâmetros que correspondam a substrings mesmo quando eles contiverem barras se eles forem prefixados com um asterisco em vez de dois pontos. Por exemplo, rotas como edit/color/:color/largecode/*largecode combinam com algo como este http://appdomain.com/edit/color/brown/largecode/code/with/slashs .

Eu mesmo testei (usando 1.1.5) e funciona muito bem. Lembre-se de que cada novo URL recarregará seu controlador, portanto, para manter qualquer tipo de estado, talvez seja necessário usar um serviço personalizado.

Aqui está outra solução que funciona bem.

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