Angularjs directiva de reemplazar el texto

¿Cómo puedo crear una directiva en angularjs que, por ejemplo, toma este elemento:

<div>Example text http://example.com</div>

Y convertir a este

<div>Example text <a href="http://example.com">http://example.com</a></div>

Ya tengo la funcionalidad escrito para auto link el texto en una función y devolver el html (vamos a llamar a la función «autoLink» ), pero no estoy a la altura de mis directivas.

También me gustaría añadir un atributo al elemento a pasar de un objeto a la directiva. por ejemplo,

<div linkprops="link.props" >Example text http://example.com</div>

Donde vínculo.props es objeto como {a: ‘bla bla’, b: ‘waa waa’} que es para pasar a la autoLink función como segundo parámetro (el primero ha sido el texto).

  • ¿hay alguna razón por qué usted necesita una directiva específica para que? ¿Hay alguna razón por la que ngHref no es una opción? (se acepta angular expresiones) docs-angularjs-org-dev.appspot.com/api/ng.directive:ngHref
  • Así que usted quiere de búsqueda de direcciones Url en el texto del elemento y crear vínculos a partir de ellos? No estoy seguro de entender la segunda parte con el enlace de «props»
InformationsquelleAutor NimmoNet | 2013-02-04

6 Kommentare

  1. 38

    Dos formas de hacerlo:

    Directiva

    app.directive('parseUrl', function () {
        var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\[email protected]?^=%&amp;\/~+#-])?/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>

    Filtro

    app.filter('parseUrlFilter', function () {
        var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\[email protected]?^=%&amp;\/~+#-])?/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>

    Nota: El 'otherProperty' es así por ejemplo, en el caso de querer pasar más propiedades en el filtro.

    jsFiddle

    Actualización: Mejora de la sustitución de algoritmo.

    • Esto es genial, aparte de una cosa. ¿Qué pasa si el texto de rellenar el campo necesita analiza primero como en este jsfiddle jsfiddle.net/CcrPz
    • Respuesta actualizada. Por favor, compruebe si ayuda.
    • La repetición de un mismo vínculo crea un problema aquí. ¿Cuál puede ser la más rápida solución para esto?
    • El uso de un normalizar función para eliminar duplicados Url de la urlPattern resultado del partido y crear una expresión regular para el reemplazo global de las direcciones Url. Verificar aquí
    • No entiendo por qué el uso de una única cita en todas partes y, luego, cuando llegue el momento de tener comillas dobles en la cadena de decidir cambiar a comillas dobles para envolver para que tenga toda esta feo escapar. ¿Por qué no puede JavaScript devs sólo se adhieren a un único o doble de la oferta, excepto cuando la conmutación será conveniente?
    • su ejemplo no funciona si una url es prefijo de otra (por ejemplo: «example.com example.com/hello»)
    • Llegué casi a la misma solución, thx 🙂 Esta solución también elegantemente elimina el mencionado anteriormente duplicado url problema.

  2. 4

    La parte superior votado respuesta no funciona si hay varios enlaces. Linky ya hace el 90% de la obra para nosotros, el único problema es que esteriliza el html por lo tanto la eliminación de html/saltos de línea. Mi solución fue simplemente editar el linky filtro (a continuación se muestra Angular 1.2.19) no desinfectar la entrada.

    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>');
        }
      };
    }]);
  3. 1

    Quería un botón de pausa que swaps de texto. aquí está cómo lo hice:

    en CSS:

    .playpause.paused .pause, .playpause .play { display:none; }
    .playpause.paused .play { display:inline; }

    en plantilla:

    <button class="playpause" ng-class="{paused:paused}" ng-click="paused = !paused">
      <span class="play">play</span><span class="pause">pause</span>
    </button>
    • ngShow/ngHide hacer lo mismo como lo que estoy haciendo aquí, pero con la ventaja de ngAnimate de trabajar con él. ngIf es bueno para las cosas que realmente quiere que se elimine de la DOM (audio/video/img elementos, por ejemplo, con un solo src.) docs.angularjs.org/api/ng/directive/ngIf
  4. 0

    Me gustaría analizar el texto en la función de enlace en la directiva:

    directive("myDirective", function(){
    
      return {
            restrict: "A",
            link: function(scope, element, attrs){
              //use the 'element' to manipulate it's contents...
            }
          }
      });
    • He probado esto, pero cuando yo uso el elemento.texto(‘bla <a href=»asd»>tea</a>’) se muestra el código html como texto
    • podría usted compartir su jsfiddle
    • Me acaba de actualizar a la pregunta como me di cuenta de que necesita más funcionalidad
  5. 0

    Inspirado por @Neal me hizo esto «no desinfectar» el filtro de la más reciente Angular 1.5.8. También reconoce las direcciones sin necesidad de ftp|http(s) pero a partir de www. Esto significa que tanto https://google.com y www.google.com será linkyfied.

    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, '&quot;'),
                    '">');
          addText(text);
          html.push('</a>');
        }
      };
    }

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea