#angularjs
#angularjs
Вопрос:
У меня возникли проблемы с реализацией пользовательской директивы с transclude: true
, которая может содержать содержимое «transclusion», использующее ngRepeat.
[Мой случай]
Я хочу реализовать набор директив, которые извлекают данные, которые они должны показывать, из службы $ http. Для этого я хочу использовать перехватчик фазы предварительной ссылки, предоставляемый Angular, чтобы я мог перехватывать данные и устанавливать их в область видимости. Таким образом, если у меня есть некоторые динамические (поскольку этот термин сильно перегружен — я имею в виду данные, структура которых неизвестна до тех пор, пока запрос не будет выполнен) данные, поступающие из сервиса, я полагаюсь на это, что я смогу извлечь список с этими динамическими данными и сохранить его внутри области видимости, затем выполнить цикл по этим данным через ngRepeat внутри HTML. Здесь возникает моя проблема…
[Моя проблема]
Angular не использует список, который я присваиваю области во время предварительной ссылки.
[A plunkr]
Я создал модуль, который иллюстрирует только проблему, с которой я столкнулся.
http://plnkr.co/edit/XQOm4KWgKxRhn3pOWqzy?p=preview
[Мой вопрос]
Я действительно верю, что такая функциональность предусмотрена angular, и я просто чего-то не хватает в головоломке.
Кто-нибудь может сказать мне, как реализовать такое поведение?
Спасибо!
Редактировать:
Спасибо rchawdry за ваш ответ. Вот некоторые подробности о моих намерениях. Чтобы упростить задачу, я попытаюсь привести вам пример. Давайте предположим, что у нас есть эти директивы:
1. «страница» — эта директива представляет собой помеченный контейнер для всего содержимого страницы. Визуально это представлено в виде некоторого div — для заголовка, для содержимого и для других необычных вещей, если это необходимо. Директива не знает, каковы ее данные, до загрузки страницы. По мере загрузки страницы директива должна извлекать информацию для себя и своих дочерних элементов из ресурса REST! Затем директива устанавливает необходимую для себя информацию (метку и другие данные) и сохраняет свое дочернее содержимое в переменной области видимости childrenList. Это создает область видимости.
2. «раздел» — этот раздел может быть дочерним по отношению к «странице». Поскольку «страница» извлекает свои данные с сервера, то информация о том, сколько «секций» имеет наша «страница», является динамической, и мы не знаем, сколько «секций» нам нужно отобразить на экране. Это зависит от списка разделов, который поступает из серверной части. Сам раздел почти такой же, как «страница» — это контейнер с надписью, с отличиями, которые — a). «раздел» — это контейнер элементов; b). «section» извлекает свои данные из своего parrent вместо выполнения HTTP-запроса $. Эта директива создает область видимости.
3. «элемент» — Для этого примера, чтобы не определять много разных элементов и не усложнять его, давайте предположим, что у меня есть один элемент, называемый «element». При необходимости он может состоять из некоторого «ввода» с «span» и «button». Он похож на «раздел» тем, что извлекает данные для отображения из своего parrent (в общем случае это «раздел» или «страница»). С другой стороны, он отличается от «раздела» тем фактом, что в нем нет преобразованного содержимого.
Теперь, когда у нас есть некоторая концепция, вот чего я пытаюсь достичь:
<page>
<element id='element1' someOtherStuffHere...></element>
<section id='static_section1' someOtherStuffHere...>
<element id='element2' someOtherStuffHere...></element>
</section>
<div class="row" ng-repeat="section in sections">
<section dynamic_id='dynamic_section'>
<div class="row" ng-repeat="elem in elements">
<element dynamic_id='dynamic_element'></element>
</div>
</section>
</div>
</page>
Ответ №1:
что ж, я полагаю, что то, чего вы пытаетесь достичь, будет возможно путем добавления ng-repeat
атрибута к преобразованному шаблону.
предполагается, что, сообщая angular о «повторении», он должен работать.
поскольку plunkr в настоящее время недоступен, я не могу выполнить какой-либо предварительный просмотр и у меня нет вашего исходного кода. Я попытаюсь вспомнить это:
template: "<div id='container'>"
"<div class='content' ng-repeat='item in [1]' ng-transclude'></div>"
"</div>"
редактировать: http://plnkr.co/edit/xba4pU666OGxBtKtcDwl?p=preview
Комментарии:
1. Я не желаю использовать область видимости локального контроллера, как раз наоборот, я не могу позволить, чтобы мои директивы имели scope: false , потому что они могут быть включены несколько раз внутри шаблона, и если это так — у меня будут адские проблемы с заполнителями… Как сказано в документации angular — если вы планируете создать директиву многократного использования, вам нужно будет использовать либо изолированную область, либо новую область для вашей директивы, возиться с контроллером не вариант…
2. Я несколько часов пытался заставить ее работать подобным образом, к сожалению, в моем случае этот взлом невозможен : (. Хотя спасибо за публикацию!. Поэтому я все еще ищу какое-то более стандартное решение angular.
3. не могли бы вы, пожалуйста, быть более конкретными?
4. Я могу попробовать. Я полагаюсь на организацию области видимости, и в этом случае, несмотря на то, что ng-repeat внутри div «content» является циклом, за один шаг он создал область видимости, так же как и ng-repeat из преобразования. Возможно, есть способ реорганизовать мой другой код вокруг этой идеи, но я действительно верю, что у этой стандартной проблемы есть стандартное решение angular. Поверьте, если я буду более конкретен в своей проблеме, это только усложнит и усугубит ситуацию.
5. Я не уверен, что я вас понимаю, но, возможно, изменение
scope:true
наscope:{}
приблизит вас? (в дополнение к взлому)
Ответ №2:
У вас проблема с областью видимости. Контроллер использует переменную, которая не определена в контроллере (arrayListItemsPre и arrayListItemsPost). Хотя они объявлены в директивах, доступ к ним в преобразованной области немного сложнее.
Простой способ — сделать следующее. При этом переменные области будут представлены контроллеру, где они могут быть использованы.
app.directive('container', function($compile) {
return {
transclude: true,
scope: true,
replace: true,
restrict: 'E',
template: "<div class='container'>"
"<div class='content' ng-transclude></div>"
"</div>",
compile: function(cElem, cAttrs) {
return {
pre : function preLink(scope, iElement, iAttrs) {
console.log("Hello from Container preLinkPhase");
scope.$parent.arrayListItemsPre = [1, 2];
},
post : function postLink(scope, iElement, iAttrs) {
scope.$parent.arrayListItemsPost = [1, 2];
}
};
}
};
});
Есть другие способы сделать это, которые лучше, но это требует понимания того, почему вы пытаетесь выполнить итерацию по переменным, которые определены в директиве. Если вы собираетесь использовать эту директиву на другой странице, которая содержит другие элементы массива, вам придется изменить код директивы.
Комментарии:
1. Спасибо за ваш ответ. В текущем случае это работает, однако мой реальный вариант немного более запутанный. Я попытался предоставить вам более подробную информацию, надеюсь, это достаточно понятно. У меня есть один вопрос. В вашем решении, используя $ parent, я устанавливаю список, с которым я буду взаимодействовать, на контроллер вне директивы (контроллер <body>). Должен ли я обращаться к этому <body>, используя $parent … $ parent для хранения моих списков, или мне просто нужно сохранить их в непосредственном $ parent директивы???
2. Способ объявления ваших директив (scope: true), каждая директива получает свою собственную область видимости, но также наследует свойства от родительской, чтобы она могла получить доступ к этим элементам свойств. В моем примере, установив свойство в родительской области видимости, любой дочерний элемент родительского элемента будет иметь доступ к переменным. Итак, допустим, у вас есть еще одна новая директива в теле. Эта директива сможет также получать доступ к переменным, установленным первой директивой (т. е. в ссылке pre или post новой директивы они могут просто использовать «scope.arrayListItemsPre» (нет необходимости указывать $ parent из-за прототипического наследования)
3. Тем не менее, обычно дурным тоном является использовать $ parent и использовать это как способ обмена информацией, потому что область действия вашей директивы будет меняться в зависимости от использования. Выше это работает нормально, но если вы добавите ng-repeat в свой
container
, вы не будете устанавливать переменные области видимости в контроллере body, это было бы в области видимости ng-repeat. Другие директивы, которые зависели от значений, установленных в теле, их не получат. Лучшим решением является использование областей изоляции и явная передача информации между родительскими / дочерними директивами.4. Установка ng-repeat в моем контейнере не является решением, потому что таким образом я смогу дублировать только весь переведенный контент, и, как видно из примера, это не тот случай. Я попытаюсь углубиться в то, как я могу реализовать управление областью изоляции, однако я скептически отношусь к тому, что это будет возможно. Спасибо за объяснение и предложения!