$ emit vs callback в родительском директиве по связям с сообществом лучший подход

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

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

например:

.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():

например:

  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');
                };
            }
        };
    });

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

попробовал найти лучший подход в Интернете, но Im все еще топал

ИЗМЕНИТЬ

Я забыл о

требуется

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

Ответ 1

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

Мои личные взгляды в стороне, хотя, и если это более "перспективный" подход, который вы ищете, подход обратного вызова, безусловно, самый безопасный. Вот почему...

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

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


Ответ 2

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

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

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

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

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

http://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');
                  }
                };
            }
        };
    });

Ответ 3

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

  • Метод обратного вызова. Это, пожалуй, самый эффективный вариант. Директива child просто вызовет один метод родительской директивы, no накладные расходы. Здесь объясняется несколько вариантов: fooobar.com/info/85274/...

  • Эмит (или, в этом отношении, широковещательный). Этот метод публикует событие для всех $scope (s) up (emit) или down (broadcast) для иерархии, относительно дорогостоящий, но он дает вам возможность смотреть и обрабатывать событие, где доступно $scope.

  • Инъекционная общая служба. Эта опция может использоваться, если вы хотите вызвать какой-либо метод, где $scope недоступен. Тем не менее, она создавала жесткую зависимость от обслуживания. Это больше pub-sub.