WedX - журнал о программировании и компьютерных науках

$emit против обратного вызова в родительском дочернем директиве лучший подход

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

это означает, что если дочерней директиве необходимо каким-то образом обновить родительскую директиву (обе имеют изолированные области действия), я должен передать функцию обратного вызова:

e.g:

.directive('filterReviewStepBox', function () {
    return {
        restrict: 'EA',
        scop: {
            //some data
        },
        template: '<div>text<reusable-dir></reusable-dir call-back="foo"></div>',
        link: function (scope, elem, attrs) {
            scope.foo = function () {
                console.log('bar');
            };
        }
    };
}).directive('reusableDir', function () {
    return {
        restrict: 'EA',
        scope: {
            callBack: '=callBack'
                //other data
        },
        template: '<div>text<button type="button" ng-click="bar"></button></div>',
        link: function (scope, elem, attrs) {
            scope.bar = function () {
                scope.callBack();
            }
        }
    };
});

или я должен использовать $emit():

e.g:

  directive('filterReviewStepBox', function () {
        return {
            restrict: 'EA',
            scope: {
                // some data
            },
            template: '<div>text<reusable-dir></reusable-dir></div>',
            link: function (scope, elem, attrs) {
                scope.$on('foo', function () {
                    console.log('bar');
                });
            }
        };
    }).directive('reusableDir', function () {
        return {
            restrict: 'EA',
            scope: { //some data
            },
            template: '<div>text<button type="button" ng-click="bar"></button></div>',
            link: function (scope, elem, attrs) {
                scope.bar = function () {
                    scope.$emit('foo');
                };
            }
        };
    });

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

пытался найти лучший подход в Интернете, но я все равно топнул

ИЗМЕНИТЬ

я забыл о

требовать

вариант. но я все еще не уверен, что это самое правильное решение. Поскольку это не позволяет мне повторно использовать дочерний элемент или внук и как бы делает директиву единым элементом цели.


  • есть опция require, которая позволяет вам получить доступ к контроллеру другой директивы. это должно позволить вам делать то, что вы хотите. 24.10.2015
  • Я понимаю, что вы говорите ... не думал об этом ... но что произойдет, если я хочу, чтобы ребенок был многоразовым? тогда ваш подход не может быть использован. 24.10.2015
  • По моему опыту, хорошо разработанные директивы должны быть автономными и должны функционировать полностью, как если бы они были единственным компонентом, существующим на странице. Если вы пытаетесь уведомить какую-то другую директиву о чем-то, то вы не самодостаточны. Почти в каждом случае, когда директива должна общаться вне себя, должно работать простое свойство с двусторонней привязкой. 24.10.2015
  • @Claies, директивы должны быть автономными и при этом должны иметь возможность связываться со своей родительской директивой или контроллером. есть много примеров, в которых вы должны выполнить какое-то обновление для родителя. двухсторонняя привязка, как правило, является подходом, который отвергается (например, angular2 и reactjs), а также в больших масштабах трудно понять, поэтому я не хочу использовать его, особенно для более сложных действий. для некоторых действий требуется какой-то обратный вызов или $emit. 24.10.2015
  • Я думаю, что оба подхода являются правильными, я лично использую оба в разных ситуациях, а также вижу плагины, использующие их. Все сводится к стандартизации (использование одного и того же подхода в аналогичном коде) и хорошей документации, чтобы ее было легче поддерживать в будущем. 26.10.2015

Ответы:


1

Для этой цели лучше всего использовать атрибут «require».

Полное руководство по директивам расскажет нам об атрибуте require: https://docs.angularjs.org/api/ng/service/$компилировать

Требовать еще одну директиву и ввести ее контроллер в качестве четвертого аргумента функции связывания. Требование принимает строковое имя (или массив строк) директивы для передачи.

Require просто сообщает директиве, что она должна найти какую-то родительскую директиву и взять ее контроллер. Вы можете указать директиву для поиска в родительских элементах с префиксом ^ и указать, является ли это требование необязательным с префиксом ?.

Я изменил ваш пример, поэтому reusableDir может вызывать контроллер filterReviewStepBox, но также может использоваться отдельно.

https://jsbin.com/gedaximeko/edit?html,js,console,output

angular.module('stackApp', [])  
.directive('filterReviewStepBox', function () {
        return {
            restrict: 'EA',
            scope: {
                // some data
            },
            template: '<div>text<reusable-dir></reusable-dir></div>',
            link: function (scope, elem, attrs) {

            },
            controller : function() {
              this.notify = function(value) {
                console.log('Notified : ' + value);
              };              
            },
            controllerAs: 'vm',
            bindToController: true
        };
    }).directive('reusableDir', function () {
        return {
            restrict: 'EA',
            scope: { //some data
            },
            require: '?^filterReviewStepBox',
            template: '<div>text<button type="button" ng-click="bar()"></button></div>',
            link: function (scope, elem, attrs, controller) {
                scope.bar = function () {
                  if (controller) {
                    controller.notify('foo');
                  }
                };
            }
        };
    });
27.10.2015
  • ваше решение использует опцию контроллера, но это также не решает мою проблему с общими директивами, которые не могут предсказать родительский контроллер, и именно поэтому я задал этот вопрос. здесь либо я определяю строгий контроллер, либо нет, это не будет работать на нескольких контроллерах, то есть вы не можете использовать его с контроллером1, а затем с контроллером2, поэтому я предпочел использовать $emit или обратные вызовы, поскольку они могут быть реализованы в общем. 27.10.2015
  • Если вы имеете в виду, что директива не знает, кого она вызывает, тогда $emit будет действительно более общим. Я бы не стал использовать обратный вызов, потому что обычно я использую transclude, поэтому мой reusableDir не будет внутри родительского шаблона. Но как вы имели в виду, что это не позволяет вам повторно использовать «дочерний элемент или внуки»? 27.10.2015
  • когда вы используете require, вы фактически вынуждены использовать родительский или родительский контроллер, поэтому, если я хочу использовать функциональность и обратный вызов в другом контроллере, я не могу... Лично меня больше привлекает $emit, чем callBacks, но я просто пытаюсь понять лучшая практика 27.10.2015

  • 2

    Лично я стараюсь не создавать собственные пользовательские события. Главным образом потому, что невероятно легко вызвать нежелательное распространение событий или всплытие (часто вызывая нежелательные дайджесты областей), но также и из-за систематического «шума», с которым в больших приложениях может стать очень трудно справиться.

    Если оставить в стороне мои личные взгляды, и если вы ищете более «защищенный от будущего» подход, подход с обратным вызовом, безусловно, самый безопасный. Вот почему...

    • Angular2 поощряет разработчиков раскрывать атрибуты onChange из директив и компонентов, которые зависят от связи между потомками и родителями. Обратите внимание, что это не более чем связанные функции, и они должны быть определены соответствующим образом в привязках или областях действия данного компонента или директивы.
    • Как и выше, Angular2 документирует метод ngOnChanges, который может быть определен любым контроллером, желающим подписаться на изменения в его привязках. Если указан, этот метод вызывается до того, как произойдут какие-либо манипуляции с DOM (с новыми связанными значениями), поэтому он является идеальным кандидатом для более «общего» взаимодействия между родителем и дочерним элементом по сравнению с текущей реализацией AngularJS $scope.$watch.

    Однако не было упомянуто, что общение через сервисы по-прежнему рекомендуется как в AngularJS, так и в Angular2.


    19.04.2016

    3

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

    1. Метод обратного вызова. Это, пожалуй, самый эффективный вариант. Дочерняя директива просто вызовет один метод родительской директивы, без накладных расходов. Здесь объясняется довольно много вариантов: https://stackoverflow.com/a/27997722/2889528

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

    3. Injectable Common Service: этот параметр можно использовать, если вы хотите вызвать какой-либо метод, где $scope недоступен. Однако это создавало жесткую зависимость от сервиса. Это больше похоже на паб-саб.

    16.04.2016
    Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

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

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]