Директива Angularjs для замены текста
Как создать директиву в angularjs, которая, например, принимает этот элемент:
<div>Example text http://example.com</div>
И преобразуйте его в это
<div>Example text <a href="#" onclick="location.href='http://example.com'; return false;">http://example.com</a></div>
У меня уже есть функциональность, написанная для автоматической ссылки на текст в функции и возврата html (позвольте вызывать функцию autoLink), но я не могу поцарапать свои директивы.
Я также хотел бы добавить атрибут к элементу, чтобы передать объект в директиву. например.
<div linkprops="link.props" >Example text http://example.com</div>
Если link.props является объектом типа {a: 'bla bla', b: 'waa waa'}, который должен быть передан функции autoLink в качестве второго параметра (первым был текст).
Ответы
Ответ 1
Два способа сделать это:
Директива
app.directive('parseUrl', function () {
var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\[email protected]?^=%&\/~+#-])?/gi;
return {
restrict: 'A',
require: 'ngModel',
replace: true,
scope: {
props: '=parseUrl',
ngModel: '=ngModel'
},
link: function compile(scope, element, attrs, controller) {
scope.$watch('ngModel', function (value) {
var html = value.replace(urlPattern, '<a target="' + scope.props.target + '" href="$&">$&</a>') + " | " + scope.props.otherProp;
element.html(html);
});
}
};
});
HTML:
<p parse-url="props" ng-model="text"></p>
Фильтр
app.filter('parseUrlFilter', function () {
var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\[email protected]?^=%&\/~+#-])?/gi;
return function (text, target, otherProp) {
return text.replace(urlPattern, '<a target="' + target + '" href="$&">$&</a>') + " | " + otherProp;
};
});
HTML:
<p ng-bind-html-unsafe="text | parseUrlFilter:'_blank':'otherProperty'"></p>
Примечание. 'otherProperty'
- это просто, например, если вы хотите передать больше фильтров в фильтр.
jsFiddle
Обновление: Улучшен алгоритм замены.
Ответ 2
Чтобы ответить на первую половину этого вопроса, без дополнительного требования к ресурсу, можно использовать фильтр Angular linky: https://docs.angularjs.org/api/ngSanitize/filter/linky
Ответ 3
Верхний проголосовавший ответ не работает, если есть несколько ссылок. Linky уже делает 90% работы для нас, единственная проблема заключается в том, что она санирует html, удаляя html/newlines. Мое решение состояло в том, чтобы просто отредактировать фильтр linky (ниже Angular 1.2.19), чтобы не дезинфицировать входные данные.
app.filter('linkyUnsanitized', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP =
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-][email protected])\S*[^\s.;,(){}<>]/,
MAILTO_REGEXP = /^mailto:/;
return function(text, target) {
if (!text) return text;
var match;
var raw = text;
var html = [];
var url;
var i;
while ((match = raw.match(LINKY_URL_REGEXP))) {
// We can not end in these as they are sometimes found at the end of the sentence
url = match[0];
// if we did not match ftp/http/mailto then assume mailto
if (match[2] == match[3]) url = 'mailto:' + url;
i = match.index;
addText(raw.substr(0, i));
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
raw = raw.substring(i + match[0].length);
}
addText(raw);
return html.join('');
function addText(text) {
if (!text) {
return;
}
html.push(text);
}
function addLink(url, text) {
html.push('<a ');
if (angular.isDefined(target)) {
html.push('target="');
html.push(target);
html.push('" ');
}
html.push('href="');
html.push(url);
html.push('">');
addText(text);
html.push('</a>');
}
};
}]);
Ответ 4
Мне нужна кнопка паузы, которая меняет текст. вот как я это сделал:
в CSS:
.playpause.paused .pause, .playpause .play { display:none; }
.playpause.paused .play { display:inline; }
в шаблоне:
<button class="playpause" ng-class="{paused:paused}" ng-click="paused = !paused">
<span class="play">play</span><span class="pause">pause</span>
</button>
Ответ 5
Я бы проанализировал текст в функции ссылки в директиве:
directive("myDirective", function(){
return {
restrict: "A",
link: function(scope, element, attrs){
// use the 'element' to manipulate it contents...
}
}
});
Ответ 6
Вдохновленный @Neal, я сделал фильтр "no sanitize" от нового Angular 1.5.8. Он также распознает адреса без ftp | http (s), но начиная с www. Это означает, что как https://google.com
, так и www.google.com
будут привязаны.
angular.module('filter.parselinks',[])
.filter('parseLinks', ParseLinks);
function ParseLinks() {
var LINKY_URL_REGEXP =
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-][email protected])\S*[^\s.;,(){}<>"\u201d\u2019]/i,
MAILTO_REGEXP = /^mailto:/i;
var isDefined = angular.isDefined;
var isFunction = angular.isFunction;
var isObject = angular.isObject;
var isString = angular.isString;
return function(text, target, attributes) {
if (text == null || text === '') return text;
if (typeof text !== 'string') return text;
var attributesFn =
isFunction(attributes) ? attributes :
isObject(attributes) ? function getAttributesObject() {return attributes;} :
function getEmptyAttributesObject() {return {};};
var match;
var raw = text;
var html = [];
var url;
var i;
while ((match = raw.match(LINKY_URL_REGEXP))) {
// We can not end in these as they are sometimes found at the end of the sentence
url = match[0];
// if we did not match ftp/http/www/mailto then assume mailto
if (!match[2] && !match[4]) {
url = (match[3] ? 'http://' : 'mailto:') + url;
}
i = match.index;
addText(raw.substr(0, i));
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
raw = raw.substring(i + match[0].length);
}
addText(raw);
return html.join('');
function addText(text) {
if (!text) {
return;
}
html.push(text);
}
function addLink(url, text) {
var key, linkAttributes = attributesFn(url);
html.push('<a ');
for (key in linkAttributes) {
html.push(key + '="' + linkAttributes[key] + '" ');
}
if (isDefined(target) && !('target' in linkAttributes)) {
html.push('target="',
target,
'" ');
}
html.push('href="',
url.replace(/"/g, '"'),
'">');
addText(text);
html.push('</a>');
}
};
}