Как динамически внедрить контроллер в AngularJS

Как установить ng-controller как выражение из $scope?

Согласно документации:

ngController — {выражение} — имя глобально доступной функции-конструктора или выражение, которое в текущей области оценивается как функция-конструктор.

Но как оценить выражение области действия в качестве контроллера для контроллеров, зарегистрированных с помощью модуля .controller?

Например:

Макет:

<div ng-controller="myExpr"></div>

JavaScript (определить контроллер):

app.controller('myCtrl', ['$scope', '$timeout', function () { ... }];

JavaScript (родительская область):

$scope.myExpr = ...;

Что должно быть в myExpr, чтобы использовать myCtrl в качестве контроллера через выражение?

Я пробовал $controller('myCtrl')... не работает...

P.S. Если контроллер был определен через глобально доступную функцию... его можно указать как myExpr. Но что делать, если он был определен именно так?


person ValeriiVasin    schedule 27.06.2013    source источник
comment
app.controller('myCtrl', [...]) возвращает результат, который может быть присвоен переменной и выражению области видимости. Тем не менее, я не понимаю, почему вы хотите сделать такую ​​​​вещь...   -  person callmekatootie    schedule 27.06.2013
comment
Если вы хотите повторно использовать функциональность одного контроллера внутри другого контроллера, вам лучше реорганизовать то, что вам нужно, в службу, которую можно внедрить во все контроллеры.   -  person Narretz    schedule 27.06.2013
comment
Я хотел бы использовать один и тот же контроллер, но он должен работать с разными службами. Например у нас есть контроллер и внутри него мы отправляем запрос на какой-то эндпойнт API (через сервис), а внутри другого представления - то же самое, но эндпоинты уже другие..   -  person ValeriiVasin    schedule 27.06.2013
comment
@callmekatootie Когда я пытаюсь сохранить результат в переменную и присвоить его выражению области видимости... Я получил ошибку: Error: Argument 'ctrl' is not a function, got Object Вы можете попробовать: jsbin.com/otakaw/8/edit   -  person ValeriiVasin    schedule 27.06.2013
comment
Я бы не стал помещать контроллеры в глобальные переменные, это просто поощряет людей небрежно относиться к своим зависимостям. Метод, который вы используете для его определения, просто прекрасен. Тем не менее, я не совсем уверен, что следую тому, что вы хотите сделать. Вам нужен контроллер, и внутри этого контроллера вам нужен еще один контроллер, который первый контроллер может переключать через переменную. Это оно? И если это так, есть ли особая причина, по которой вы не можете использовать маршруты и ng-view? Изменить: неважно, теперь увидел js bin. Я взгляну.   -  person Erik Honn    schedule 27.06.2013
comment
Я использую ng-view и маршруты. У меня есть две вкладки: Фильтры и Группы. Мы делаем абсолютно одинаковые вещи (разница очень маленькая). Внутри них у нас есть ng-repeat, и у каждого элемента есть свой контроллер. Глобальный контроллер переключается через ng-view, но внутри ng-repeat я не могу изменить контроллер в зависимости от ng-view... это шаблон с жестко запрограммированным ng-controller=Something... и я мог предоставить только FilterCtrl или GroupCtrl ... GroupsCtrl и GroupCtrl должны работать с GroupService, FiltersCtrl и FilterCtrl должны работать с FilterService.... как внедренные зависимости..   -  person ValeriiVasin    schedule 27.06.2013
comment
Итак, у вас есть два повтора с двумя наборами объектов. Вы хотите перебрать один из них в зависимости от того, на какой вкладке вы находитесь, но использовать один и тот же HTML, потому что два разных типа объектов почти идентичны? В таком случае, зачем вообще нужны контроллеры? У вас уже есть предметы из повтора. Я думаю, что я что-то упускаю здесь :)   -  person Erik Honn    schedule 27.06.2013
comment
@ErikHonn На каждой вкладке есть только ng-repeat. Элементы для ng-repeat извлекаются через службы Filter или Group, которые работают с разными конечными точками. Контроллеры нужны потому, что у каждого элемента в цикле повторения есть наборы действий: переименовать, удалить и т.д...   -  person ValeriiVasin    schedule 27.06.2013
comment
И эти действия различаются или даже конфликтуют между типами, поэтому иметь один контроллер немного неприятно. Теперь я понимаю. Я думаю, что вы хотите, чтобы здесь отображались ваши действия через службу (которую вы затем можете поменять местами, как если бы вы хотели поменять местами контроллер), я попробую это в корзине, чтобы посмотреть, что у меня получится.   -  person Erik Honn    schedule 27.06.2013
comment
@ErikHonn Спасибо за вашу помощь.   -  person ValeriiVasin    schedule 27.06.2013


Ответы (1)


Выражения, которые принимает ng-controller, немного странные. Таким образом, вы можете сделать это, немного по-другому написав свой контроллер (но читайте ниже, почему вы, вероятно, этого не хотите).

function myCtrl($scope) {
  $scope.value = 'Stuff';
}

Это контроллер и будет работать как обычно для этого случая. Как в этом примере: http://jsbin.com/ubevel/2/edit

Так почему бы и нет?
Во-первых, это не лучший способ определить вещи с точки зрения тестирования. Во-вторых, это позволяет вам динамически устанавливать контроллер при загрузке, но не позволит вам что-то изменить после этого. Если вы измените значение myExpr после загрузки страницы, контроллер не изменится.

Итак, что делать?
Я настоятельно рекомендую вместо этого рассмотреть возможность использования службы. Поменяйте местами свои действия, снабдив внешний контроллер службой, которую вы затем измените таким же образом, как сейчас пытаетесь изменить внутренний контроллер. Что-то вроде: http://jsbin.com/ubevel/5/edit

Этот сервис можно заменить на лету, его изменение изменит действия, доступные в области действия.

Вы также можете использовать include, но это приведет к дублированию html. Я лично согласен с этим, так как я против повторного использования html для объектов двух разных типов (рано или поздно вы захотите изменить один, но не другой, и это становится беспорядком). Но против этого многие будут возражать.



Дополнительное примечание: возможно, есть более удобные способы сделать это с помощью контроллеров, я, вероятно, не рассматривал все аспекты, но я просто не думаю, что контроллеры являются правильным инструментом для этого случая.

person Erik Honn    schedule 27.06.2013
comment
Хорошие моменты. Но это не то, чего я действительно хочу. Я временно решил эту проблему с помощью директивы ng-include и копирования моего html-кода для элемента ng-repeat. Реальный вопрос: как использовать выражения для директивы ng-controller с контроллерами, объявленными как module.controller('ctrl', [/** dependencies */]);. Но два ответа могут быть использованы как хитрый способ достичь цели. P.S. если AngularJS имеет эту функцию, а это значит, что авторы позволяют нам делать это в некоторых случаях... может быть, даже для моей цели :) - person ValeriiVasin; 28.06.2013