AngularJS — ngRepeat внутри преобразования пользовательской директивы работает не так, как ожидалось

#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 в моем контейнере не является решением, потому что таким образом я смогу дублировать только весь переведенный контент, и, как видно из примера, это не тот случай. Я попытаюсь углубиться в то, как я могу реализовать управление областью изоляции, однако я скептически отношусь к тому, что это будет возможно. Спасибо за объяснение и предложения!