Using jquery or JS how do you turn a string into a link?

3.6k views Asked by At

So I have a piece of HTML that looks something like this...

<p>This is some copy. In this copy is the word hello</p>

I want to turn the word hello into a link using jquery.

<p>This is some copy. In this copy is the word <a href="">hello</a></p>

That in itself is not too hard. My problem is that if the word is already apart of a link like the example below...

<p>In this copy is the <a href="">word hello</a></p>

I don't want that to end up with a link within a link...

<p>In this copy is the <a href="">word <a href="">hello</a></a></p>

Any help would be much appreciated.

9

There are 9 answers

0
Jay Blanchard On

First keep the words while getting rid of the current anchor tag, if there is one:

$('a').each(function() {
    $(this).replaceWith(this.childNodes);
 });

Then do a replace on the string that you need to work with

$('p').html($('p').text().replace('hello', '<a href="">hello</a>'));
3
Tom On

A little regex should do the trick (Update, see below):

$(document).ready(function(){
    var needle = 'hello';
    $('p').each(function(){
        var me = $(this),
            txt = me.html(),
            found = me.find(needle).length;
        if (found != -1) {
            txt = txt.replace(/(hello)(?!.*?<\/a>)/gi, '<a href="">$1</a>');
            me.html(txt);
        }
    });
});

Fiddle: http://jsfiddle.net/G8rKw/

Edit: This version works better:

$(document).ready(function() {
    var needle = 'hello';
    $('p').each(function() {
        var me = $(this),
            txt = me.html(),
            found = me.find(needle).length;
        if (found != -1) {
            txt = txt.replace(/(hello)(?![^(<a.*?>).]*?<\/a>)/gi, '<a href="">$1</a>');
            me.html(txt);
        }
    });
});

Fiddle: http://jsfiddle.net/G8rKw/3/

Edit again: This time, "hello" is passed as a variable to the regex

$(document).ready(function() {
    var needle = 'hello';
    $('p').each(function() {
        var me = $(this),
        txt = me.html(),
        found = me.find(needle).length,
        regex = new RegExp('(' + needle + ')(?![^(<a.*?>).]*?<\/a>)','gi');
        if (found != -1) {
            txt = txt.replace(regex, '<a href="">$1</a>');
            me.html(txt);
        }
    });
});

Fiddle: http://jsfiddle.net/webrocker/MtM3s/

2
Ian Wootten On

This jQuery solution searches for a particular term and doesn't create a link if it finds it's followed by a closing link tag.

var searchTerm = "hello";

$('p:contains("' + searchTerm + '")').each(function(){
    var searchString = $(this).html();
    var searchIndex = searchString.indexOf(searchTerm);
    var startString = searchString.substr(0 , searchIndex);
    var endString = searchString.substr(searchIndex + searchTerm.length);
    if(endString.match(/<\/a>/g)) return;
    $(this).html(startString + "<a href=''>" + searchTerm + "</a>" + endString);
});​

Here's a link to a jsfiddle for it.

0
Selvakumar Arumugam On

Wrote a simple function to check if the replacing text is enclosed by a link tag. See below,

DEMO: http://jsfiddle.net/wyUYb/4/

function changeToLink (sel, txt) {
   var regEx = new RegExp(txt, 'g');
   $.each($(sel), function (i, el) {
       var linkHTML = $(el).html();
       var idx = linkHTML.indexOf(txt);

       if (idx >= 0) {
           var t = linkHTML.substring(idx);
           //Fix for IE returning tag names in upper case http://stackoverflow.com/questions/2873326/convert-html-tag-to-lowercase
           t = t.replace(/<\/?[A-Z]+.*?>/g, function (m) { return m.toLowerCase(); })
           var closingA = t.indexOf('</a>');

           t = t.substring(0, closingA);
           if (closingA != -1) {
               t = t.substring(0, closingA); 
               if (t.indexOf('<a') < txt.length) {
                   return;
               }
           }               

           linkHTML = linkHTML.replace(regEx, '<a href="">' + txt + '</a>');
           $(el).html(linkHTML);
       }           
   });
}

Also even if you add a nested link your browser would simply change it to two links. May be because it is not legal to use nested links. See below,

Also documented in W3C for Nested Links

12.2.2 Nested links are illegal

Links and anchors defined by the A element must not be nested; an A element must not contain any other A elements.

Since the DTD defines the LINK element to be empty, LINK elements may not be nested either.

And that is why browser handles nested link as separate links.

http://jsfiddle.net/H44jE/

See the firebug inspect on right bottom of the image.

enter image description here

1
Dave Kirk On

Can you not test for the parent element of the word before turning it into a link?

if (parent != 'a') {
   // do your thing
}

(I don't know what the actual jQuery would be to test this)

EDIT

The following will replace the word in all <p> elements that DO NOT contain a link in them.

May not work exactly as required but hopefully points you in the direction

// get all p elements that contain the word hello but DO NOT have link in them
var elems = $('p:contains("hello")').not(':has(a)');


// replace instances of hello in the selected p elements
$(elems).html($(elems).html().replace(/(hello)/g,'<a href="new">$1</a>'));

Live Demo on JSBin

0
RDK On

Try to user .replace jquery function something like this:

var str = $('p').html().replace('(some)','(to some)');
0
A.M. D. On

You need the jquery :not selector, or .not().

The API docs cover this well, you should be able to select your content, then deselect links within it.

http://api.jquery.com/not-selector/

0
Adil On

You can do it this way,

Live Demo

$('p').each(function(){    
    if($(this).find('a').length > 0) return;  
    lastSpaceIndex = $(this).text().lastIndexOf(' ');
    if(lastSpaceIndex  == -1)
        lastSpaceIndex = 0;    
    WordToReplace = $(this).text().substring(lastSpaceIndex);
    idx = $(this).text().lastIndexOf(WordToReplace);
    resultstring = $(this).text().substring(0, idx); 
    $(this).html(resultstring);
    $(this).append($( "<a href='#'>" + WordToReplace  + "</a>"));
});​
0
Ian Lunn On

Instead of searching for the word and trying to find its parent, search for the link and check the word it contains:

if($('a').text() === "hello"){
  //already linked
}else{
  //not linked
}