Replacing multiple <li> texts at the same time on hover using Javascript (not CSS!)

I have a requirement to change the text on hover of multiple menu items at once, but I cannot use CSS and cannot give each individual element its own CSS class. What I would like to do is when the mouse is over somewhere .menu-wrapper

, Javascript replaces each text of the text <li>

with the corresponding replacement text.

I have a script that works great for one element:

    <div class="menu-wrapper">
        <ul>
            <li>WORD1</li>
        </ul>
    </div>

      

JavaScript:

var originalText = $('.menu-wrapper > ul > li').text();

$('.menu-wrapper').hover(function () {

    var $p = $(this).find('li');
    $p.fadeOut(300, function () {
        $(this).text('replacement word 1').fadeIn(300);
    });
}, function () {
    // set original text
    $(this).find('li').fadeOut(300, function () {
        $(this).text(originalText).fadeIn(300);
    });
});

      

But obviously, if you add multiple elements <li>

, they will be split because they only store one .text () variable and concatenate all entries after the first mouseout event.

I tried using an operator switch

to find the .text () value and change the text value accordingly, but it didn't work (my Javascript is weak ...).

I would appreciate any help with this. I only have four elements to replace the text so that any script can be repeated as needed no problem. Normally I would give everyone their own class ID and use what I already have, but unfortunately I can't.

Please do not suggest using CSS as I already know how to do this, but I need to use Javascript for this.

I couldn't find this question elsewhere.

Thank!

+3


source to share


5 answers


The main problem is the first line:

var originalText = $('.menu-wrapper > ul > li').text();

      

This will get all the text from all elements of the collection:

What you can do is store this text for each element using jQuery data()

, looping through the elements and dealing with the instances:

$('.menu-wrapper > ul > li').each(function(){
     $(this).data('original', $(this).text());
});

      

Then in the "t" part tout> read the previously saved text using data () again

$(this).find('li').fadeOut(300, function () {
    var originalText = $(this).data('original');
    $(this).text(originalText).fadeIn(300);
});

      



Several options for new text:

Put it in your markup as a data attribute

<li data-alt_text="alternate word">

      

Then in the mousenter the hover callback:

$p.fadeOut(300, function () {
    $(this).text($(this).data('alt_text')).fadeIn(300);
});

      

Or inject an array and use the first loop to add the array data to the element

var words=['W1','W2','W3'];
// first argument of "each" is "index"
$('.menu-wrapper > ul > li').each(function(index){
     $(this).data(
         {
             'alt_text': words[index],
             'original', $(this).text()
           }
      );
});

      

+2


source


You can use javascripts' ability to assign any property to an object (element) to store the original text instead of storing it in a single variable (or use the jQuery data function to do the same)

$('.menu-wrapper li').hover(function () {    
    $(this).fadeOut(300, function () {
        this.originalText = $(this).text();
        $(this).text('replacement word 1').fadeIn(300);
    });
}, function () {
    // set original text
    $(this).fadeOut(300, function () {
        $(this).text(this.originalText).fadeIn(300);
    });
});

      

fiddle

For this, instead of directly linking to the .menu-wrapper

div, you can use .menu-wrapper li

to bind to individual li elements inside the div. After that, the original text can be saved until it is changed. The same can be done beforehand by storing all values, the advantage of this method is that you always keep the most recent value in case the text is dynamically changed after startup.

To compose replacement texts to li elements, without changing the html safeest it would be to link replacement text. The simplest is an index based solution:



var replacements = ['replacement Word1', 'for word2' , 'third time\ a charm'];

$('.menu-wrapper li').hover(function () {    
    var $this=  $(this);
    $this.fadeOut(300, function () {
        $this.data('originalText', $this.text()).
        text(replacements[$this.index()]).fadeIn(300);
    });
}, function () {
    // set original text
    $(this).fadeOut(300, function () {
        $(this).text($(this).data('originalText')).fadeIn(300);
    });
});

      

fiddle

For completeness, this would be an alternative when using the li text (assuming the text can be used as a property):

var replacements ={ 
    WORD1 : 'replacement Word1',
    WORD2 : 'for word2',
    WORD3: 'third time\ a charm'
 };

$('.menu-wrapper li').hover(function () {    
    var $this=  $(this);
    $this.fadeOut(300, function () {
        $this.data('originalText', $this.text()).
        text(replacements[$this.text()]).fadeIn(300);
    });
}, function () {
    // set original text
    $(this).fadeOut(300, function () {
        $(this).text($(this).data('originalText')).fadeIn(300);
    });
});

      

fiddle

+1


source


Here's a short and simple solution to your problem:

var originalText;
$('.menu-wrapper').hover(function () {

var $p = $(this).find('li');
    $p.fadeOut(300, function () {
        this.originalText = $(this).text(); // STORES VALUE BEFORE REPLACEMENT
        $(this).text('replacement word 1').fadeIn(300);
    });
}, function () {
    $(this).find('li').fadeOut(300, function () {
        $(this).text(this.originalText).fadeIn(300);
    });
});

      

Just store the value of this element in originalText before replacing it.

0


source


We can use two arrays to store the original text and the new text. And then use $ .each to iterate over each of the lis and use their index to replace the text.
HTML:

<div class="menu-wrapper">
    <ul>
        <li>WORD1</li>
        <li>WORD2</li>
        <li>WORD3</li>
    </ul>
</div>

      

jQuery:

var originaltext = ['Word1','Word2','Word3'];
var newText = ['New text1','New text2','New text3'];
$('.menu-wrapper').hover(function () {
  $('.menu-wrapper li').each(function(i){
    $this = $(this);
     $this.html(newText[i])   
  });
}, function(){
    $('.menu-wrapper li').each(function(i){
      $this = $(this);
      $this.html(originaltext[i])   
    });

      

});

jsfiddle

0


source


Since all the other answers here use jQuery, I'll add one with vanilla js.

For this we will need to use javascript closure. This is used so that when the fade is complete, we have (a) the element that just disappeared, and (b), more importantly, an index into the originalStrings array. (B) is more important here because the target element is code that already exists - we could easily pass the original element to the callback function. However, we really need an index or string corresponding to each element. The closure provides the means for this.

The following code will eject all / any matching elements and then fade out after the text has changed.

Using the equations found here: Math: Ease In, Ease Change the offset using a time bound Hermite curve . We can then create code that will fade / move / scale the pitch / volume, etc. etc. I did this and ended up with a few functions that make simple animation easier. I've included mini versions of these below for a complete all-in-one solution that doesn't use any other resources.

<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
window.addEventListener('load', onDocLoaded, false);

function onDocLoaded()
{
    document.getElementById('goBtn').addEventListener('click', onButtonClick, false);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// animation stuff
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function cubicHermite(a,b,d,e,c){var g=a*a,f=g*a;return(2*f-3*g+1)*b+(f-2*g+a)*e+(-2*f+3*g)*d+(f-g)*c}
function interp(a,b,d,e,c){var g,f;f=e/(a/2+b+d/2);g=f*a/2;f*=b;return c<=a?cubicHermite(c/a,0,g,0,f/b*a):c<=a+b?g+f*(c-a)/b:cubicHermite((c-a-b)/d,g+f,e,f/b*d,0)}
function linear(a){return a}
function cubic(a){return interp(0.35,0.3,0.35,1,a)}
function doAnimStep(a,b,d,e,c){a<=b?(setTimeout(function(){doAnimStep(a,b,d,e,c)},d),e(a/b),a++):void 0!=c&&null!=c&&c()}
function doAnim3(totalMs, stepCallbackFunc, doneCallbackFunc)
{
    var stepDelay = 1000 / 60.0;        // set anim to 60 fps
    var numSteps = (totalMs / stepDelay)>>0;
    setTimeout( doAnim3TimeoutCallback, stepDelay );
    function doAnim3TimeoutCallback()
    {
        doAnimStep(0, numSteps, stepDelay, stepCallbackFunc, doneCallbackFunc);
    };
}
function animFadeOut(elem, callback){ doAnim3(500,function(raw){elem.style.opacity=1-cubic(raw)},callback); }
function animFadeIn(elem, callback) { doAnim3(500,function(raw){elem.style.opacity=cubic(raw)},callback); }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////




var replacementStrings = [ "replacement 1", "I'm next", "mee too", "fourth item" ];
function onButtonClick(evt)
{
    var originalStrings = [];
    var targetLiElems = document.querySelectorAll('.menu-wrapper > ul > li');
    for (var i=0,n=targetLiElems.length;i<n;i++)
    {
        var curElem = targetLiElems[i];
        originalStrings.push(curElem.innerText);
        animFadeOut(curElem, createFunc(i) );
    }
    function createFunc(i)
    {
        return function(){ var curElem = targetLiElems[i]; curElem.innerText = replacementStrings[i]; animFadeIn(curElem); };
    }
}
</script>
<style>
</style>
</head>
<body>
    <button id='goBtn'>Change the text</button>
    <div class="menu-wrapper">
        <ul>
            <li>WORD1</li>
            <li>WORD2</li>
            <li>WORD3</li>
            <li>WORD4</li>
        </ul>
    </div>
</body>
</html>

      

0


source







All Articles