Как добавить динамические всплывающие подсказки angularjs ui к существующей разметке?
Относительно новый для угловых. Помогите мне понять, что происходит здесь!
То, что я в конечном счете пытаюсь выполнить: Учитывая блок текста в моем html (скажем, в элементе абзаца), я хочу динамически добавлять всплывающие подсказки (точнее, всплывающие подсказки) для выбранных слов в тексте. Например, если пользователь вводит мир "привет" в окно поиска, все экземпляры "привет" в абзаце будут отображать всплывающую подсказку при наведении курсора, отображая какое-то сообщение как определение или что-то в этом роде.
ПРИМЕЧАНИЕ. Я не думаю, что это было изначально изначально, но блок текста, к которому я хочу добавить всплывающую подсказку, уже находится в html, и не будет иметь никакой разметки-метки-метки Это. Для иллюстрации см. fiddle.
Я сделал это в jQuery... теперь я пытаюсь заставить его работать в angularjs!
Моя первая попытка состояла в том, чтобы использовать настраиваемый фильтр с регулярным выражением, которое вставляет тег "a" с атрибутами всплывающей подсказки в абзац в соответствующих местах. Новая разметка появляется, но не кажется "видимой" angularjs (еще не совсем уверенной в терминологии, но я думаю, что она не получается "связана"??).
Здесь проблема иллюстрируется на jsfiddle:
http://jsfiddle.net/petersg5/pF33a/2/
(1) Первая строка на выходе имеет рабочую всплывающую подсказку "foo"... она просто имеет атрибуты всплывающей подсказки непосредственно в разметке. Сгенерированный html:
<a href="#" tooltip-placement="top" tooltip="basic tooltip" class="ng-scope">foo</a>
(2) Во второй строке используется ng-bind-html и имеет атрибуты, но не рабочая всплывающая подсказка. Сгенерированный html:
<a href="#" tooltip-placement="top" tooltip="tooltip via ng-bind-html">foo</a>
(3) Третья строка использует фильтр и имеет атрибуты, но не рабочую всплывающую подсказку. Сгенерированный html:
<a href="#" tooltip-placement="top" tooltip="tooltip via filter">foo</a>
Мой главный вопрос: как решить задачу, описанную выше?
Вторичный вопрос - это понимание того, что происходит в каждом из приведенных выше примеров. Я заметил, что прямой вывод в (1) имеет класс "ng-scope", вставленный angular в сгенерированную разметку. Другим двум недостает этого, но у них есть класс привязки ng, вставленный в родительский тег p. Не уверен, что происходит здесь, но я думаю, что это имеет какое-то отношение к моей проблеме.
У меня такое чувство, что решение может включать директиву, но я не уверен, как применить эту директиву к существующему тексту (т.е. тег p уже в разметке).
Спасибо!
EDIT: обновил jsfiddle, чтобы более точно отразить проблему (четвертая строка на выходе)
Ответы
Ответ 1
Правильный способ обработки HTML
будет директивой angular, давайте сделаем директиву (скажем dynamic-tooltip
), которая принимает два параметра
- сообщение с подсказкой
- ваше слово поиска
В HTML
<p dynamic-tooltip="my message" tooltip-element="searchElement">
Hello World check out my foo bar app
</p>
searchElement
будет связываться с любой моделью, например
<input type="search" ng-model="search">
<input type="button" value="Search" ng-click="searchElement = search">
Здесь, когда вы нажимаете кнопку search
, значение, введенное в поле поиска, будет установлено в searchElement
Определение директивы:
app.directive('dynamicTooltip', function($compile) {
return {
restrict: 'A',
scope: {
tooltipElement: '=',
dynamicTooltip: '@'
},
link: function(scope, element, attrs) {
var template = '<a href="#" tooltip-placement="top" tooltip="' + scope.dynamicTooltip + '">{{tooltipElement}}</a>';
scope.$watch('tooltipElement', function(value) {
var previousTooltip = element.find('a');
angular.forEach(previousTooltip, function(item, i) {
var el = angular.element(item);
el.replaceWith(el.text());
});
var searchText = scope.tooltipElement;
if (searchText) {
replaced = element.html().replace(new RegExp(searchText, "g"), template);
element.html(replaced);
}
$compile(element.contents())(scope);
});
}
}
})
Директива $watch
tooltip-element
, поэтому, когда вы меняете значение, сначала он пытается удалить предыдущие всплывающие подсказки, затем пытается сопоставить ваш search-word
, если он найден, затем создайте всплывающую подсказку.
Проверьте Демо
Ответ 2
EDIT:
Я думаю, что неправильно понял ваше требование. Особенно после того, как вы заметили, что уже используете модуль ui-boostrap angular.
Проблема здесь, я думаю, заключается в том, что новые атрибуты, которые вы прикрепляете, не скомпилированы Angular, поэтому директива tooltip
никогда не запускается. Вам нужно запустить недавно присоединенный HTML/DOM через компиляцию (элемент) (область).
Пример директивы. Обратите внимание, что это не является полным, рассматривайте его скорее как псевдокод, чем что-либо еще, но оно должно служить ориентиром для того, как это сделать. В принципе, вы можете использовать любой jQuery, который вы хотите в директиве, важно отметить, что "elem", который вы получаете в функции ссылок, - это тот же самый элемент, к которому привязана директива. Кроме того, вам нужно вызывать $compile (your_element) (область) на любом HTML/DOM, который вы создаете и присоединяете.
<p tooltip-tag="the_tag" text="My tooltip text">This is my tooltip the_tag test</p>
myApp.directive('tooltipTag', ['$compile', function($compile) {
return {
scope: {
text: '@' // Create isolate scope as this is a reusable component, we don't want to clutter parent scope
},
link: function(scope, elem, attrs) {
// Elem is here the <p> element, as jqLite/jQuery element.
// Put whatever logic you want here, feel free to use jQuery if you want
// I guess you want to copy out the text, search for 'the_tag' (which you can find in 'attrs.tooltipTag') in the text inside the <p></p> and then replace the content.
// Replace content elem.
elem.html(replaced_html); // Contains text with the_tag replaced with <a href="whatever" tooltip="{{text}}" etc..>the_tag</a>
var to_compile = elem.children('a');
// Finally, compile and attach to scope with
$compile(to_compile)(scope);
}
}
}])
Это, вероятно, наивный подход, но я не полностью знаю ваши требования. Но это должно дать вам представление о возможном способе решить эту проблему.
Я думаю, что вы приближаетесь к проблеме неправильно. При использовании Angular существует общее правило, которое: Если вы изменяете DOM, вам (почти всегда) нужна директива.
Итак, что здесь не так?
Я не слишком хорошо знаком с реализацией всплывающей подсказки Bootstrap, но я бы предположил, что он никогда не забирает недавно добавленные атрибуты "подсказки". Я верю, что причина, по которой он работает в первом примере, заключается в том, что связанный с подсказкой код выполняет поиск DOM для атрибутов подсказки при загрузке страницы, но добавление его после этого - нет. (Пожалуйста, исправьте меня, если я ошибаюсь).
Итак, как вы можете это исправить?
Я считаю, что вы хотите добавить подсказки динамически каким-то образом? Я думаю, что angular -ui bootstrap уже имеет директивы, поддерживающие это, например. ui-tooltip="{{variable.on.scope}}"
. См. Ссылку ниже.
Или, если вам нужно что-то еще, вы должны создать свою собственную директиву. Сначала директивы могут быть страшными, но они (на мой взгляд) являются самой важной особенностью angular и довольно просты в использовании, когда вы ее повесили.
По сути, при создании новой директивы вы можете передавать данные, определяющие текст, который вы хотите в всплывающей подсказке. Внутри ссылки (scope, elem, attrs) функция в вашей директиве, вы можете прикрепить всплывающую подсказку (используя функцию Bootstrap elem.tooltip()) к элементу, являющемуся элементом, к которому применяется директива.
Если вам нужно также добавить элемент <a>
, вы можете использовать переход, который немного более продвинут.
Если вы не знакомы с директивами, прочитайте об этом и спросите, нужна ли вам дополнительная помощь. Или просто проверьте angular -ui-bootstrap (есть версии для обоих Bootstrap 3 и 2):
http://angular-ui.github.io/bootstrap/