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, отложенной загрузкой контроллера

Другие вопросы по тегам