Передача поточного обсягу до служби AngularJS


106

Чи правильно передавати "струм" $scopeслужбі AngularJS?

Я знаходжусь у ситуації, коли я маю службу $, знаючи, що її споживає лише один контролер, і я хотів би мати посилання на сферу використання контролера в самих методах обслуговування $.

Це філософськи правильно?

Або я б краще транслювати події до $ rootScope, а потім змусити мій контролер їх слухати?


1
Чи можете ви, можливо, повідомити нам конкретніше, що ви намагаєтесь зробити? Можливо, натискання сфери на послугу взагалі не потрібно?
ganaraj

Ну, це не так складно. Просто я хотів би мати можливість отримати доступ до $scopeвластивостей і зателефонувати, $scope.$applyколи це потрібно.
SC

Крім того, скажіть, що я хочу застосувати зміни, що надходять від служби $ на область $. Сподіваюся, зараз зрозуміліше.
SC

8
Я пропоную вам поставити властивості $ range, до яких ви хочете, щоб ваша послуга отримала доступ до самої послуги (замість того, щоб їх мати у контролері). Служби є кращими місцями для зберігання моделей / даних, ніж контролери.
Марк Райкок

@MarkRajcock Я також намагаюся зрозуміти це питання. В даний час я просто викликаю службу і приєднуючи дані, що передаються до контролера $scope... як би контролер безпосередньо отримав доступ до даних у сервісі і передав їх перегляду, не роблячи цього?
drjimmie1976

Відповіді:


67

Щоб повідомити контролеру про те, коли відбувається асинхроніка, використовуйте кутові обіцянки .

Щоб спровокувати те $apply, вам не потрібен обсяг, ви можете зателефонувати $rootScope.$apply, оскільки немає різниці, викликаючи його в певному діапазоні або в корені.

Щодо зчитування змінної, було б краще, якби ви отримали параметри. Але ви також можете прочитати його з області в якості параметра об'єкта, але я б перейшов до параметра, який зробив би ваш інтерфейс служби набагато зрозумілішим.


Я думаю, що це відповідь, яка краще вирішує мої сумніви для початківців AngularJS.
SC

@Caio Cunha Чи не могли б ви розширити, чому це не гарна ідея пройти рамки? У мене виникає саме ця проблема, я хочу додати деякі речі $scopeчерез дзвінок до служби за допомогою executeSql()функції async . Розглядаючи 3 варіанти (1), використовуйте зворотний виклик функції async, потім дзвоніть $scope.$apply... це працює, але некрасиво (2) перейти $scopeдо функції async, потім зателефонувати theScope.$apply()... це також працює (3) використовуйте обіцянку. .. ще не пробував цього. Чому обіцянка найкращий спосіб? Дякую!
drjimmie1976

15

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

Завдання контролерів - це маніпулювати конкретною моделлю, тоді як служба повинна вирішувати глобальні завдання. Я б скоріше дотримувався цієї парадигми, а не змішував речі.

Про це говорять документи

Сервіс

Кутові послуги - одиночні кнопки, які виконують конкретні завдання, спільні для веб-додатків

Контролер

У Angular, контролер - це функція JavaScript (тип / клас), яка використовується для збільшення екземплярів кутового діапазону, виключаючи кореневу область.

PS: Крім того, якщо вам потрібно переварити, ви можете також ввести $ rootScope у вашій службі.


2
Дякую. Чудова відповідь. Заглиблюючись у свою ситуацію, справа в тому, що я користуюсь Сервісом, тому що хочу одинаку. Службу споживає лише один контролер, але цей контролер можна було кілька разів інстанціювати протягом життєвого циклу програми, тому я дуже хочу, щоб Сервіс завжди знаходився в одному стані.
SC

У будь-якому випадку роз'яснення щодо виклику $applyабо $digest$ rootScope мають для мене цілком сенс.
SC

1
Я все одно триматиму його окремо в Сервісі для тестування.
bluehallu

Якщо функціональність притаманна одному екземпляру контролера, ви можете пропустити реалізацію послуги, але в іншому випадку - ні, оскільки ви жертвуєте можливістю поділяти стан між цими екземплярами. Крім того, тільки тому, що сьогодні існує єдиний тип контролерів, це не означає, що завтра не буде іншого контролера, який може використовувати функціонал. Крім того, сервіс може уникнути здуття контролера. Тому питання не стільки в тому, чи є єдиний контролер, а в тому, в чому полягає функціональність.
Нік

9

Так. Ви можете передавати область $ в службу, коли ініціалізуєте її. У конструкторі сервісів ви можете призначити область для чогось подібного._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;

});

1
+1, однак, я хотів би бачити спосіб автоматичного пізнання кожного контролера кожного $scopeразу, коли цей контролер вводить послугу - щоб не довелося викликати метод у сервісі та переходити $scopeдо нього вручну .
Коді

2
@Cody Я не рекомендую, оскільки це суперечить ін'єкції залежності
Coldstar

Домовились, +1 за те, що мене збили! Можливо, м'ясники DIP також - я б сказав, ризикуючи бути зайвими.
Коді

Ви тут змішуєте послуги з фабриками. У цьому рішенні використовується фабрика, яка відрізняється від послуги. Основна відмінність полягає в тому, що служба повертає (однотонний) об'єкт. Тоді як завод повертає функцію, яка може бути екземпляром ( new MyFunction()). Питання стосувалося послуги, де дзвінки new- це не варіант.
Карвапалло

@Karvapallo Добре. Я вважаю, що у вугільній службі відносяться завод, послуга та постачальник (нг-ват)?
користувач12121234

6

Я особисто вважаю, що перехід $scopeдо послуги - це погана ідея , оскільки це створює своєрідну циркулярну посилання: контролер залежить від послуги, а сервіс залежить від сфери роботи контролера.

Крім того, що вони заплутані в стосунках, такі речі в кінцевому підсумку стають на шляху сміття.

Мій кращий підхід полягає в тому, щоб помістити об’єкт домену в область контролера і передати його службі. Таким чином сервіс працює незалежно від того, використовується він у контролері чи, можливо, всередині іншої служби в майбутньому.

Наприклад, якщо служба повинна виштовхувати та виконувати елементи з масиву errors, моїм кодом буде:

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

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

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


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). Наскільки я розумію, сервіс повинен генерувати масив журналів на основі параметра (тобто в цьому випадку вказівник). Для мене це погана картина, оскільки сервіси є одинаковими в кутку. Якщо реалізація послуги добре запрограмована, вона повинна генерувати масив у внутрішній змінній (щоб вона залишалася однотонною). Тому не має сенсу ініціалізувати змінну поза службою.
Soldeplata Saketos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.