Angular: как работать с директивой, состоящей из двух частей

Я реализую директиву, которая в основном берет список сносок для вставки в основной текст с функциональностью всплывающих окон. У меня есть директива text-notes, предназначенная для родительского элемента, который динамически загружает содержимое и связанные с ним текстовые заметки. Текущий шаблон начинается примерно так:

<div class="body" data-ng-bind-html="content" data-text-notes></div>
<div id="text-notes"></div>

Без атрибута data-text-notes все правильно отображается из ng-bind-html:

<div class="body" data-ng-bind-html="content">
  Content with some footnote attached.
  More content, with another footnote.
</div>

Желаемый результат с добавлением data-text-notes выглядит примерно так:

<div class="body" data-ng-bind-html="content" data-text-notes>
  Content with some footnote attached.<a href="#fn1">[fn1]</a>
  More content, with another footnote.<a href="#fn2">[fn2]</a>
</div>
<div id="text-notes">
  <p id="fn1">[fn1] Some footnote text</p>
  <p id="fn2">[fn2] Another bit of footnote text</p>
</div>

Контент визуализируется через ng-bind-html и ведет себя точно так, как хотелось бы. Раздел text-notes скрыт с помощью CSS, а содержимое каждой сноски должно отображаться как всплывающее окно (которое, вероятно, необходимо реализовать как часть директивы или как связанную директиву).

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

function TextNotes($timeout) {
    // We use `$timeout` to ensure that the digest cycle has finished and thus
    // that the page is laid out before updating it.
    $timeout(function() {
      var a, insertAtID, insertBefore, targetEl;

      for (var n = 0; n < scope.textNotes.length; n++) {
        // Create a link to the note.
        a = document.createElement('a');
        a.setAttribute('class', 'text-note');
        a.setAttribute('href', '#' + scope.textNotes[n].id);
        a.setAttribute('data-hg-note-popover');
        a.appendChild(document.createTextNode("†"));

        // Insert the link element after the verse number.
        insertAtID = scope.textNotes[n].ref;
        targetEl = document.getElementById(insertAtID);
        insertBefore = targetEl.firstChild.nextSibling;
        targetEl.insertBefore(a, insertBefore);
      }
    });

    // Separately, and after a delay so that the render above can occur without
    // blocking, insert the notes themselves. Build the string to insert, then
    // insert it separately do avoid updating the DOM a gazillion times via
    // innerHTML changes.
    $timeout(function() {
      var html = '', notesEl, notesId;

      for (var n = 0; n < scope.textNotes.length; n++) {
        // Create the element itself, inserting it at the end of the document.
        notesId = 'text-notes';
        notesEl = document.getElementById(notesId);
        if (notesEl === null) {
          notesEl = document.createElement('div');
          notesEl.setAttribute('id', notesId);
          document.getElementsByTagName('body')[0].appendChild(notesEl);
        }

        html += scope.textNotes[n].content;
      }
      notesEl.innerHTML = html;
    }, 100);
  }

  return {
    link: link,
    restrict: 'A'
  }
}

angular.module('myModule').directive('TextNotes', ['$timeout', TextNotes]);

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

Я достаточно внимательно прочитал саму документацию по Angular, а также просмотрел несколько примеров, но это первая директива substantive, которую я реализовал, и мне эта реализация не нравится: она < em>работает, но не совсем правильно. Более того, я не уверен, насколько хорошо это будет сочетаться с необходимостью делать всплывающие окна.


person Chris Krycho    schedule 22.05.2015    source источник
comment
Я думаю, вам было бы полезно использовать ng-repeat для отображения HTML   -  person Cerbrus    schedule 22.05.2015
comment
@Cerbrus, это тоже была моя мысль, я просто все еще думаю, как лучше всего это сделать - и, возможно, бесполезно, элементы <p> в заметках предварительно визуализируются (хотя я мог бы это изменить). <div id="text-notes"><p ng-repeat="note in a_text_notes_obj_or_list">{{note.content}}</p></div> или подобное…   -  person Chris Krycho    schedule 22.05.2015


Ответы (1)


Как насчет того, чтобы иметь что-то вроде:

<div class="body" data-ng-bind-html="content"></div>
<div id="text-notes">
    <p ng-repeat="note in notes" ng-attr-id="{{note.id}}">[{{note.id}}]{{note.text}}</p>
</div>

таким образом, вам больше не нужна директива... или, может быть, я неправильно понял пример.

Изменить:

Если добавленный html является директивой, которую необходимо скомпилировать, вам нужно сделать что-то вроде:

$compile(a)(scope); // compile the link before adding it to the dom
// append to dom.

Хотя вы можете захотеть запустить $compile только один раз после того, как вы добавили все ссылки - из соображений производительности.

person sirrocco    schedule 22.05.2015
comment
Это шаг в правильном направлении, и он вполне может сработать для самих заметок. Однако мне нужно вставить ссылки в отображаемый контент в первом div body/content. (Я обновлю вопрос, чтобы отразить это). Это та часть, которую я делаю динамически. Отображение содержимого заметок более прямолинейно, и я согласен, что подход ng-repeat должен сработать. - person Chris Krycho; 22.05.2015
comment
Что ж, в этой части невозможно обойти то, что вы делаете в директиве... так как вам нужно разобрать html и сделать замену.. - person sirrocco; 22.05.2015
comment
Я надеялся, что это не так, но это имеет смысл. Есть ли что-нибудь необходимое, чтобы убедиться, что эти вставленные элементы правильно скомпилированы на этапе link, чтобы к ним можно было прикрепить собственную директиву (для всплывающего окна)? - person Chris Krycho; 22.05.2015
comment
Редактирование очень полезно; это примерно то, что я думал, что мне нужно будет сделать, поэтому очень приятно знать, что я на правильном пути. Спасибо! - person Chris Krycho; 22.05.2015