AngularAMD + ui-router + имя динамического контроллера?
Я пытаюсь написать обобщенный маршрут в своем приложении и на лету разрешить вид и имена контроллеров на основе параметров маршрута.
У меня есть следующий код, который работает:
$stateProvider.state('default', angularAMD.route({
url: '/:module/:action?id',
templateUrl: function (params) {
var module = params.module;
var action = module + params.action.charAt(0).toUpperCase()
+ params.action.substr(1);
return 'app/views/' + module + '/' + action + 'View.html';
},
controller: 'userController',
}));
Тем не менее, я не могу найти способ динамического разрешения имени контроллера. Я пытался с помощью resolve
как описано здесь, но UI-маршрутизатор, кажется, обрабатывает разрешение иначе, чем Angular-route.
Есть указатели?
РЕДАКТИРОВАТЬ: я уже пытался использовать controllerProvider
но это не работает для меня (например, следующий код просто возвращает жестко закодированное имя контроллера, чтобы проверить, действительно ли он работает):
controllerProvider: function () {
return 'userController';
}
Дает мне следующую ошибку:
Ошибка: [ng:areq] Аргумент 'userController' не является функцией, получил неопределенное значение
http://errors.angularjs.org/1.3.3/ng/areq?p0=userController&p1=not%20aNaNunction%2C%20got%20undefined
1 ответ
Это ссылка на работающего плунжера.
решение
Нам нужны две функции UI-Router:
- разрешить (загрузить недостающие фрагменты кода js)
- controllerProvider (см. цитаты из документации ниже)
angularAMD - определение main.js
Это будет наш main.js, который содержит интеллектуальное преобразование controllerName - controllerPath:
require.config({
//baseUrl: "js/scripts",
baseUrl: "",
// alias libraries paths
paths: {
"angular": "angular",
"ui-router": "angular-ui-router",
"angularAMD": "angularAMD",
"DefaultCtrl": "Controller_Default",
"OtherCtrl": "Controller_Other",
},
shim: {
"angularAMD": ["angular"],
"ui-router": ["angular"],
},
deps: ['app']
});
контроллеры:
// Controller_Default.js
define(['app'], function (app) {
app.controller('DefaultCtrl', function ($scope) {
$scope.title = "from default";
});
});
// Controller_Other.js
define(['app'], function (app) {
app.controller('OtherCtrl', function ($scope) {
$scope.title = "from other";
});
});
app.js
Во-первых, нам понадобится какой-нибудь метод, преобразующий параметр (например, id) в имя контроллера. Для наших целей тестирования давайте использовать эту наивную реализацию:
var controllerNameByParams = function($stateParams)
{
// naive example of dynamic controller name mining
// from incoming state params
var controller = "OtherCtrl";
if ($stateParams.id === 1) {
controller = "DefaultCtrl";
}
return controller;
}
.state()
И это было бы, наконец, наше определение государства
$stateProvider
.state("default", angularAMD.route({
url: "/{id:int}",
templateProvider: function($stateParams)
{
if ($stateParams.id === 1)
{
return "<div>ONE - Hallo {{title}}</div>";
}
return "<div>TWO - Hallo {{title}}</div>";
},
resolve: {
loadController: ['$q', '$stateParams',
function ($q, $stateParams)
{
// get the controller name === here as a path to Controller_Name.js
// which is set in main.js path {}
var controllerName = controllerNameByParams($stateParams);
var deferred = $q.defer();
require([controllerName], function () { deferred.resolve(); });
return deferred.promise;
}]
},
controllerProvider: function ($stateParams)
{
// get the controller name === here as a dynamic controller Name
var controllerName = controllerNameByParams($stateParams);
return controllerName;
},
}));
Проверьте это здесь, в этом рабочем примере
документация
Как описано здесь: $ stateProvider, для state(name, stateConfig)
мы можем использовать controller
а также controllerProvider
, Некоторая выдержка из документации:
controllerProvider
...
controller
(необязательно) строковая функция
Контроллер fn, который должен быть связан с новой связанной областью или именем зарегистрированного контроллера, если он передан в виде строки. Опционально, ControllerAs могут быть объявлены здесь.
controller: "MyRegisteredController"
controller:
"MyRegisteredController as fooCtrl"}
controller: function($scope, MyService) {
$scope.data = MyService.getData(); }
controllerProvider
(опционально) функция
Инъекционная функция провайдера, которая возвращает фактический контроллер или строку.
controllerProvider:
function(MyResolveData) {
if (MyResolveData.foo)
return "FooCtrl"
else if (MyResolveData.bar)
return "BarCtrl";
else return function($scope) {
$scope.baz = "Qux";
}
}
...
разрешить
resolve
(необязательно) объект
Необязательный
map<string, function>
из зависимостей, которые должны быть введены в контроллер. Если какие-либо из этих зависимостей являются обещаниями, маршрутизатор будет ожидать разрешения их ВСЕХ, прежде чем будет создан экземпляр контроллера...
Т.е. давайте использовать controllerProvider
:
... для динамического разрешения имени контроллера...
В случае, если вам удалось попасть сюда, возможно, вы захотите проверить другое подобное решение с RequireJS - angular-ui-router с requirejs, отложенной загрузкой контроллера