Передача текущей области в службу AngularJS

106

Правильно ли передавать «текущий» $scopeсервису AngularJS?

Я нахожусь в ситуации, когда у меня $ service, зная, что он используется только одним контроллером, и я хотел бы иметь ссылку на область действия контроллера в самих методах $ service.

Это правильно с философской точки зрения?

Или мне лучше транслировать события в $ rootScope, а затем заставить мой контроллер их слушать?

SC
источник
1
Не могли бы вы сообщить нам более конкретно, что вы пытаетесь сделать? Может быть, вообще не нужно распространять область видимости на сервис?
ganaraj
Что ж, это не так уж и сложно. Просто я хотел бы иметь доступ к $scopeсвойствам и вызывать $scope.$applyпри необходимости.
SC
Кроме того, скажите, что я хочу применить изменения, поступающие из службы $, в область $. Надеюсь, теперь стало яснее.
SC
8
Я предлагаю вам поместить свойства $ scope, к которым вы хотите, чтобы ваша служба имела доступ, в саму службу (вместо того, чтобы иметь их в контроллере). Сервисы - лучшее место для хранения моделей / данных, чем контроллеры.
Марк Райкок
@MarkRajcock Я тоже пытаюсь разобраться в этой проблеме. В настоящее время я просто вызываю службу и прикрепляю обслуживаемые данные к контроллеру $scope... как контроллер может напрямую обращаться к данным в службе и передавать их в представление, не делая этого?
drjimmie1976

Ответы:

67

Чтобы сообщить контроллеру, когда происходит что-то асинхронное, используйте обещания Angular .

Чтобы спровоцировать $apply, вам не нужна область видимости, вы можете вызвать $rootScope.$apply, поскольку нет разницы, вызывая ее в определенной области или в корне.

Что касается чтения переменных, лучше бы вы получили параметры. Но вы также можете прочитать его из области видимости как параметр объекта, но я бы выбрал параметр, который сделает ваш интерфейс службы намного более понятным.

Кайо Кунья
источник
Я думаю, что это ответ, который лучше решает мои сомнения новичка в AngularJS.
SC
@Caio Cunha Не могли бы вы подробнее рассказать, почему не рекомендуется передавать прицел? У меня именно эта проблема, я хочу добавить кое-что $scopeчерез вызов службы с использованием executeSql()функции async . Рассматривая 3 варианта (1) используйте обратный вызов для функции async, затем вызовите $scope.$apply... это работает, но уродливо (2) перейдите $scopeк функции async, затем вызовите theScope.$apply()... это также работает (3) используйте обещание. .. еще не пробовал. Почему обещание - лучший способ? Спасибо!
drjimmie1976
15

Я бы сказал, что если ваша функциональность предназначена только для одного контроллера, тогда вам не нужна услуга.

Задачи контроллеров - управлять конкретной моделью, тогда как служба должна иметь дело с глобальными задачами. Я бы предпочел придерживаться этой парадигмы, чем что-то путать.

Это то, что говорят документы

обслуживание

Сервисы Angular - это одиночные приложения, которые выполняют определенные задачи, общие для веб-приложений.

Контроллер

В Angular контроллер - это функция JavaScript (тип / класс), которая используется для дополнения экземпляров angular Scope, за исключением корневой области.

PS: Кроме того, если вам нужно дайджест, вы также можете вставить $ rootScope в свой сервис.

Ф Лекщас
источник
2
Спасибо. Отличный ответ. Если углубиться в мою ситуацию, дело в том, что я использую Service, потому что мне нужен синглтон. Службу использует только один контроллер, но этот контроллер может быть создан несколько раз в течение жизненного цикла приложения, поэтому я действительно хочу, чтобы служба всегда находилась в одном и том же состоянии.
SC
В любом случае пояснение о вызове $applyили вызове $digest$ rootScope для меня полностью осмысленно.
SC
1
Я бы по-прежнему держал его отдельно в Сервисе для тестирования.
bluehallu
Если функциональность относится к одному экземпляру контроллера, вы можете пропустить реализацию службы, но в противном случае нет, поскольку вы жертвуете возможностью совместного использования состояния между этими экземплярами. Кроме того, то, что сегодня существует один тип контроллера, не означает, что завтра не будет другого контроллера, который мог бы использовать эту функциональность. Кроме того, служба может избежать раздувания контроллера. Так что вопрос не столько в том, есть ли один контроллер, сколько в функциональности.
Ник
9

Да. Вы можете передать $ scope в службу при ее инициализации. В конструкторе службы вы можете назначить область видимости примерно так :_scope, а затем ссылаться на область внутри службы!

angular.module('blah').controller('BlahCtrl', function($scope, BlahService) {

    $scope.someVar = 4;

    $scope.blahService = new blahService($scope);

});

angular.module('blah').factory('blahService', function() {

    //constructor
    function blahService(scope) {
        this._scope = scope;

        this._someFunction()
    }

    //wherever you'd reference the scope
    blahService.prototype._someFunction = function() {

        this._scope['someVar'] = 5;

    }

    return blahService;

});
user12121234
источник
1
+1, однако, я хотел бы увидеть способ автоматически узнавать каждый контроллер $scopeвсякий раз, когда данный контроллер внедряет службу, чтобы не вызывать метод службы и вручную переходить $scopeк ней.
Cody
2
@Cody Я не рекомендую это, поскольку это противоречит Injection Dependency Injection
Coldstar
Согласен, +1 за то, что сбил меня! Вероятно, мясники DIP тоже - я бы сказал, рискуя оказаться лишним.
Коди
Здесь вы смешиваете услуги с фабриками. В этом решении используется фабрика, которая отличается от службы. Основное отличие состоит в том, что служба возвращает объект (одноэлементный). В то время как фабрика возвращает функцию, которая может быть создана ( new MyFunction()). Вопрос касался услуги, newв которую нельзя позвонить .
Karvapallo
@Karvapallo Хороший вопрос. В качестве контраргумента я считаю, что сервисы angular относятся к фабрике, сервису и провайдеру (ng-wat)?
user12121234
6

Я лично считаю, что переход $scopeк службе - плохая идея , потому что он создает своего рода циклическую ссылку: контроллер зависит от службы, а служба зависит от области действия контроллера.

Такие вещи, как эта, не только сбивают с толку с точки зрения отношений, но и мешают сборщику мусора.

Я предпочитаю поместить объект домена в область контроллера и передать его службе. Таким образом, служба работает независимо от того, используется ли она внутри контроллера или, возможно, внутри другой службы в будущем.

Например, если служба должна выталкивать и извлекать элементы из массива errors, мой код будет:

var errors = [];
$scope.errors = errors;
$scope.myService = new MyService(errors);

Затем служба взаимодействует с контроллером, оперируя errors. Конечно, я должен быть осторожен и никогда не стирать всю ссылку на массив, но, в конце концов, это общая проблема JS.

Я бы никогда не хотел использовать трансляцию $applyи / или подобные вещи, потому что имхо хорошие OO-практики всегда будут превосходить любые Angular-magics.

Марко Фаустинелли
источник
1
Есть ли разница между этим кодом и этим ?:$scope.errors = []; $scope.myService = new MyService($scope.errors);
Soldeplata Saketos
@SoldeplataSaketos - Да, это так. errorsживет независимо от $scope. В этом весь смысл этого ответа. Пожалуйста, проверьте ссылку, которую я предоставил в тексте. Ура.
Марко Фаустинелли
1
Если я правильно понимаю ваш код, $scope.errorsуказывает на var errors, а ошибки переменных кажутся мне избыточными, поскольку это просто еще один указатель. Одна подобная ситуация , я думаю, и что это явно избыточными этот кусок кода: const errors = errors2 = errors3 = []; $scope.errors = errors;. Согласны ли вы с тем, что только предоставленный вами фрагмент кода кажется var errors = []излишним?
Soldeplata Saketos
Нет, это не так. Повторяю слово в слово: errorsживет независимо от $scope. Вам необходимо понимать, что такое объект домена, а также что такое varназначение. Если предоставленной мной ссылки недостаточно, есть много других материалов.
Марко Фаустинелли,
Что ж, это будет зависеть исключительно от реализации функции MyService(errors). Насколько я понимаю, служба должна создавать массив журналов на основе параметра (в данном случае указателя). Для меня это плохой образец, так как сервисы являются одиночными в angular. Если реализация службы хорошо запрограммирована, она должна сгенерировать массив во внутренней переменной (чтобы она оставалась одноэлементной). Следовательно, нет смысла инициализировать переменную вне сервиса.
Soldeplata Saketos