Подтвердить что ты не робот

DOM-манипуляция в сервисах AngularJS

Хорошо известно, что вы должны манипулировать элементами DOM внутри директив при использовании AngularJS.

Однако, похоже, что в некоторых случаях использование DOM внутри службы приемлемо. Misko Hevery говорит об этом здесь. Вы также можете найти пример в диалоговом окне Bootstrap UI Dialog.

Объяснение Misko довольно расплывчато, поэтому мне было интересно, как вы определяете, когда вам нужно помещать DOM внутри службы вместо директивы.

4b9b3361

Ответ 1

Директива, с которой она определена, всегда привязана к DOM node. Поэтому, когда вы определяете директиву, он "расширяет" или заменяет DOM node, к которому он присоединен.

В определенных ситуациях (например, в диалогах) вы не сможете присоединить узлы DOM к любому определенному родительскому элементу. В этих случаях использование службы имеет смысл, и контроллер все еще может оставаться вне бит DOM, поскольку манипуляция DOM будет инкапсулирована в службу.

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

Итак, базовый и простой тест: "Может ли этот бит кода DOM Manipulation быть прикреплен к DOM node?" Если да, то директива. Если нет, то услуга.

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

Ответ 2

В то время как я думаю, что Ганарадж описал, что сказал Мишко, вы могли (и, возможно, должны) утверждать, что код манипуляции DOM для модального диалога (например) можно поместить в DOM node.

Один из подходов состоит в том, чтобы все директивы диалогового окна, прикрепленные к DOM, затем использовали ng-show для условного отображения. Затем вы можете общаться с модальным диалогом, используя либо $rootScope, либо лучше: службу.

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

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

Ответ 3

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

У меня есть элементы на основе директивы, которые реагируют на положение мыши в глобальном масштабе (например, они перемещаются или меняются каким-то образом на основе положения мыши). Существует неопределенное количество этих элементов, и они не относятся к какому-либо конкретному местоположению в приложении (поскольку это элемент GUI и может принадлежать любому контейнеру в любом месте). Если бы я придерживался строгой логики dom angular только в директивах ", это было бы менее эффективно, потому что все элементы разделяют логику, связанную с разбором позиции мыши (эффективно), которая вращается вокруг window.requestAnimationFrame..

Если бы я связал эту логику с директивой, у меня был бы цикл прослушивания /raf, привязанный к каждому отдельному экземпляру. Хотя он все равно будет СУХОЙ, это было бы неэффективно, так как на каждом шагу мыши вы стреляли в одного и того же слушателя, который возвращал бы тот же результат для каждого отдельного элемента.

В этом случае лучше всего перевести это в сервис, несмотря на то, что он является логикой на основе dom, и зарегистрировать каждый экземпляр директивы для службы для вызова той же логики на основе экземпляра против выполняемой логики, которая была бы дублирована для каждый экземпляр.

Помните, что в то время как angular содержит некоторые очень полезные советы о том, как структурировать код, что не делает его пулевым доказательством каким-либо образом жестким и быстрым правилом, поскольку он не может охватывать все варианты использования. Если вы видите дыру, в которой "лучшие практики", похоже, терпят неудачу, потому что вы на самом деле правильно понимаете лучшие практики, и теперь у вас есть причина для нарушения правил по назначению.

Это только мои 2 цента!

Ответ 4

Я согласен с @dudewad. В конце дня услуга (factory, поставщик, значение) представляет собой шаблон шаблона angular с ограничением реализации в качестве одноэлементного. Я считаю важным, чтобы вы получили доступ к DOM через элемент, который передается в функцию директивной ссылки, а не с использованием документов или других глобальных подходов. Тем не менее, я не думаю, что важно, чтобы логика, которую вы применяете к элементу dom, который вы получаете из директивы, живет в одном модуле. Для причин SRP может быть выгодно немного разбить код с помощью службы, поскольку у вас может быть особенно сложная логика, что имеет смысл сосредоточиться на тестировании или вы можете использовать логику в нескольких директивах как указано @dudewad.

Ответ 5

Один из недостатков использования метода манипуляции DOM, основанного на изменении переменной (т.е. ng-show="isVisible"), заключается в том, что манипуляция DOM происходит после следующего цикла цикла javascript turn (при обновлении isVisible). Возможно, вам понадобится обновить DOM.

Например, общий сценарий отображает "счетчик" во время перехода на новый маршрут/состояние. Если вы должны были установить $scope.isVisible = true в событии $routeChangeStart/$stateChangeStart, а затем $scope.isVisible = false в событии $routeChangeSuccess/$stateChangeSuccess, вы никогда не увидите свой ng-show, так как весь маршрут/состояние изменение происходит в течение одного поворота javascript. Было бы лучше использовать .show() и .hide() в этих событиях, чтобы вы действительно видели spinner.

чтобы вернуть все это обратно и сделать его релевантным для вопроса OP - в ситуации, когда манипуляция DOM является отображаемой "spinner", я бы сделал это во время службы, и я сделал бы это с прямым DOM методы манипуляции, а не полагаться на изменение модели.