Суть:
директива типа “атрибут”, значением идет имя поддирективы, которую необходимо динамически подгрузить. Может быть удобно в случае, когда в зависиомти от условия мы должны выводить различные компоненты.
Предистория:
В проекте (на AngularJS) стала задача вывести список сущностей, каждая из которых имеет свойства и представление (директивы). Но сложность заключается в том, что сущности могут буть разных типов, совершенно разных: с различным представлением и поведением. Вопрос: “что делать, если хочется все вывести через ng-repeat?”. Одну директиву в духе god-antipattern, где будет сразу все возможные варианты поведения и отображения, лепить не хотелось. Хотелось использовать разные, чтобы потом еще можно было делать новые и они автоматически подхватывались. Но как их подгружать?
Решение:
Для динамической сборки директивы нам нужен сервис $compile. В итоге получилось такое( выкладываю упрощенный вариант):
html:
<div ng-repeat="item in items"> <itemDirective></itemDirective> </div>
а внутри директивы itemDirective:
element.append($compile(angular.element('<' + $scope.item.type + '/>'))($scope));
После чего пришла мысль “а почему бы это не оформить в виде директивы, которая будет подгружать в себя в зависимости от параметра другую директиву“.
И код преобразился следующим образом:
<div ng-repeat="item in items"> <itemDirective ng-directive="{{item.type}}"></itemDirective> </div>
А в директиве:
element.append($compile(angular.element('<' + attrs.ngDirective + '/>'))($scope));
attrs.$observe('ngDirective', function(directive) { element.html(''); element.append($compile(angular.element('<' + directive + '/>'))($scope)); });
Очень бы хотелось услышать конструктивную критику.
Идея пришла под вдохновлением от прочтения этой статьи.
UPD: как подсказали в сообществе:
- лучше не смешивать логику с представлением(хранить имя директивы в контролере)
- следить за утечками памяти, ибо в данном случае новая директива создает много вотчеров, которые потом никто не зачищает
- использовать для данной задачи ngSwitch