0

I have a bunch of dynamically generated H1 tags. I want to randomly select 1 word within the tag, and wrap it in italic tags.

This is what I have so far, the problem is, it is taking the first h1's dynamically generated content, and duplicating it to every h1 on the page. Other than that, it works.

Any ideas?

var words = $('h1').text().split(' ');

// with help from http://stackoverflow.com/questions/5915096/get-random-item-from-array-with-jquery

var randomWord = words[Math.floor(Math.random()*words.length)];

// with more help from http://stackoverflow.com/questions/2214794/wrap-some-specified-words-with-span-in-jquery

$('h1').html($('h1').html().replace(new RegExp( randomWord, 'g' ),'<i>'+randomWord+'</i>'));

My ultimate goal

<h1>This is a <i>title</i></h1>
<h1><i>This</i> is another one</h1>
<h1>This <i>is</i> the last one</h1>

All of the titles will be dynamically generated.

http://codepen.io/anon/pen/uskfl

Steven Morgan
  • 79
  • 4
  • 13
  • It's also applying your styling to every word in the tag (is that what you want?) http://jsfiddle.net/929DE/ – scrowler Jun 13 '14 at 02:07
  • You need to target your code at a specific `h1` tag from the bunch, and stick with it! Like this: http://jsfiddle.net/929DE/1/ – scrowler Jun 13 '14 at 02:08
  • No, this code is selecting a single word from the tag. See edit for my goal/detail. – Steven Morgan Jun 13 '14 at 02:09
  • You are write because it never selects a new word it picks one and done. There is few ways you can attack this, store every used word in an array and have a loop that checks if word used generate another or post.. Also you can just have a loop that goes over every H1 and checks it up against new generated one and again if matched get new word.. you need an IF and a LOOP .. Best of luck! – I am Cavic Jun 13 '14 at 02:10
  • That's kind of a bummer, so I can't have something sniff out every H1 on the page and do it. Has to be specifically targeted? – Steven Morgan Jun 13 '14 at 02:11
  • No, you can loop over them all if you want, and if you do that - use `$(this)` to reference each one as you go rather than updating them all using `$('h1')` as your selector – scrowler Jun 13 '14 at 02:12
  • Here's a demo of what you're after: http://jsfiddle.net/scrowler/KQRUv/ – scrowler Jun 13 '14 at 02:14

2 Answers2

4

The problem is $('h1') creates a collection of all of the h1 tags in the page.

You can use a function callback of the html() method which will loop over every h1 and treat them as separate instances

$('h1').html(function(index, existingHtml) {
    var words = existingHtml.split(' ');
    var randomWord = words[Math.floor(Math.random() * words.length)];
    return existingHtml.replace(new RegExp(randomWord, 'g'), '<i>' + randomWord + '</i>');

});

see html() docs ( scroll 1/2 way down page, function argument was not in earlier versions)

charlietfl
  • 170,828
  • 13
  • 121
  • 150
2

You can use jQuery's .each() to iterate through the h1s.

$('h1').each(function(){
    var words = $(this).text().split(' ');
    var randomWord = words[Math.floor(Math.random()*words.length)];
    $(this).html(
        $(this).html().replace(new RegExp( randomWord, 'g'),'<i>'+randomWord+'</i>')
    );
});

Demo: http://jsfiddle.net/RT25S/1/

Edit: I just noticed a bug in my answer that is also in your question and probably in the other answers.

In titles like this is another one, is is italicised in both is and this. scrowler commented that when the selected word is in the title multiple times all of them will be italicised, but I doubt you intended for partial words to be italicised.

The fixes are relatively simple. Just check for spaces before and after the word. You also have to allow for words at the beginning and end of the title using the ^ and $ metacharacters.

Ideally we could use \b, which is a "word boundary", instead but it doesn't seem to work when words end with non-alphanum characters.

You should also probably escape the randomly-selected word before including it in a regex in case it contains any special characters. I added the escaping regex from Is there a RegExp.escape function in Javascript?.

The updated code:

$('h1').each(function(){
    var words = $(this).text().split(' ');
    var randomWord = words[Math.floor(Math.random()*words.length)];
    // Escape the word before including it in a regex in case it has any special chars
    var randomWordEscaped = randomWord.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

    $(this).html(
        $(this).html().replace(
            //new RegExp( '\\b' + randomWordEscaped + '\\b', 'g' ),
            new RegExp( '(^| )' + randomWordEscaped + '( |$)', 'g' ),
            '<i> ' + randomWord + ' </i>'
        )
    );
});

And the updated JSFiddle: http://jsfiddle.net/RT25S/3/

Note that I added spaces after and before the <i> tags because the regex now captures them. (This still works for words at the beginning/ends of titles because HTML ignores that whitespace.)

Community
  • 1
  • 1
freshtop
  • 706
  • 8
  • 17