Динамическая маршрутизация AngularJS
В настоящее время у меня есть приложение AngularJS с встроенной маршрутизацией.
Он работает, и все в порядке.
Мой файл app.js выглядит следующим образом:
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: '/' });
}]);
В моем приложении встроена CMS, где вы можете копировать и добавлять новые html файлы в каталог /pages.
Я бы хотел по-прежнему проходить через поставщика маршрутизации, хотя даже для новых динамически добавленных файлов.
В идеальном мире шаблон маршрутизации будет:
$routeProvider.when('/ имя_файла', {templateUrl: '/pages/Итак, если мое новое имя страницы было "contact.html", я хотел бы, чтобы angular забирал "/contact" и перенаправлялся на "/pages/contact.html".
Возможно ли это? и если да, то как?!
Обновление
Теперь у меня это в моей конфигурации маршрутизации:
$routeProvider.when('/page/:name', { templateUrl: '/pages/home.html', controller: CMSController })
и в моем CMSController:
function CMSController($scope, $route, $routeParams) {
$route.current.templateUrl = '/pages/' + $routeParams.name + ".html";
alert($route.current.templateUrl);
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];
Это устанавливает текущий шаблон urrl в правильное значение.
Однако теперь я хотел бы изменить ng-view с новым значением templateUrl. Как это достигается?
Ответы
Ответ 1
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'
});
}
]);
- Добавление * позволяет работать с несколькими уровнями каталогов динамически.
Пример: /страница/автомобили/продажа/список будут улавливаться у этого провайдера.
Из документов (1.3.0):
"Если templateUrl является функцией, он будет вызываться со следующим Параметры:
{Array.} - параметры маршрута, извлеченные из текущего $location.path(), применяя текущий маршрут"
Также
когда (путь, маршрут): метод
- путь может содержать именованные группы, начинающиеся с двоеточия и заканчивающиеся звездой: например: name. Все символы с нетерпением хранятся в $routeParams под заданным именем, когда маршрут соответствует.
Ответ 2
Ok решил это.
Добавлено решение для GitHub - http://gregorypratt.github.com/AngularDynamicRouting
В моей конфигурации маршрутизации app.js:
$routeProvider.when('/pages/:name', {
templateUrl: '/pages/home.html',
controller: CMSController
});
Затем в моем контроллере 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'];
С#views, являющимся моим <div id="views" ng-view></div>
Теперь он работает со стандартной маршрутизацией и динамической маршрутизацией.
Чтобы проверить это, я скопировал about.html, назвал его portfolio.html, изменил часть содержимого и ввел /#/pages/portfolio
в мой браузер, и hey presto portfolio.html был отображен....
Обновление
Добавлены $apply и $compile в html, чтобы динамический контент мог быть введен.
Ответ 3
Я думаю, что самый простой способ сделать это - это разрешить маршруты позже, например, спросить маршруты через json. Проверьте, что я делаю factory из $routeProvider во время фазы конфигурации через $обеспечить, поэтому я могу продолжать использовать объект $routeProvider на этапе запуска и даже в контроллерах.
'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();
});
});
Ответ 4
В паттернах URI $routeProvider вы можете указать переменные параметры, например: $routeProvider.when('/page/:pageNumber' ...
, и получить доступ к нему в вашем контроллере через $routeParams.
В конце страницы $route есть хороший пример: http://docs.angularjs.org/api/ng.$route
EDIT (для отредактированного вопроса):
Система маршрутизации, к сожалению, очень ограничена - есть много дискуссий по этой теме, и некоторые решения были предложены, а именно путем создания нескольких именованных видов и т.д. Но прямо сейчас директива ngView обслуживает только ОДИН просмотр в маршрута, на индивидуальной основе. Вы можете обойти это несколькими способами - проще будет использовать шаблон представления в качестве загрузчика с тегом <ng-include src="myTemplateUrl"></ng-include>
($ scope.myTemplateUrl будет создан в контроллере).
Я использую более сложное (но более чистое, для более крупных и более сложных проблем) решение, в основном пропуская услугу $route вообще, что подробно описано здесь:
http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm
Ответ 5
Не уверен, почему это работает, но возможно использование динамических (или подстановочных знаков) маршрутов в angular 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: '<div ng-include="templateUrl">Loading...</div>',
controller: 'DynamicController'
}).
controller('DynamicController', function ($scope, $routeParams) {
console.log($routeParams);
$scope.templateUrl = 'partials/' + $routeParams.a;
}).
example.com/foo → загружает "foo" partial
example.com/bar- > загружает "bar" partial
Нет необходимости в каких-либо корректировках в ng-view. Случай "/: a" - единственная переменная, которую я обнаружил, которая будет достигать этого.. '/: foo' не работает, если ваши частичные файлы не являются foo1, foo2 и т.д.... '/: a' работает с любыми частичными имя.
Все значения запускают динамический контроллер - поэтому нет "иначе", но я думаю, что это то, что вы ищете в динамическом или подстановочном сценарии маршрутизации.
Ответ 6
Как и в случае с AngularJS 1.1.3, теперь вы можете сделать именно то, что хотите, используя новый параметр catch-all.
https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5
От фиксации:
Это позволяет routeProvider принимать параметры, которые соответствуют подстроки, даже если они содержат слэши, если они имеют префикс со звездочкой, а не с двоеточием. Например, такие маршруты, как edit/color/:color/largecode/*largecode
будет соответствовать чему-то подобному http://appdomain.com/edit/color/brown/largecode/code/with/slashs
.
Я сам тестировал его (используя 1.1.5), и он отлично работает. Просто имейте в виду, что каждый новый URL-адрес перезагружает ваш контроллер, поэтому, чтобы сохранить какое-либо состояние, вам может потребоваться использовать настраиваемую службу.
Ответ 7
Вот еще одно решение, которое работает хорошо.
(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;
}
})();