Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Truncate Text with JavaScript with "Read More" and "Read Less"

Tags:

javascript

My apologies if I've framed this question incorrectly or if it's been asked and answered previously, my search turned up similar Q&A's which were based around JQuery and I'm looking for a pure JavaScript solution.

var len = 100;
var p = document.getElementById('shrinkMe');
if (p) {

 var trunc = p.innerHTML;
 if (trunc.length > len) {

trunc = trunc.substring(0, len);
trunc = trunc.replace(/\w+$/, '');

trunc += '<a href="#" ' +
  'onclick="this.parentNode.innerHTML=' +
  'unescape(\''+escape(p.innerHTML)+'\');return false;">' +
  'Read More<\/a>';
p.innerHTML = trunc;
  }
}

JSFiddle

The fiddle truncates text with JavaScript, however in it's current state it's for a single occurrence which isn't quite what I need. I have multiple occurrences of 'shrinkMe' as a div id in the body of my html and as .getElementById is used this will need to be tweaked as at the moment when "Read More" is clicked it expands all occurrences simultaneously. I believe that changing to .getElementsByClassName may be the solution to enable me to have multiple occurrences of a class name opposed to being restricted to one instance of .getElementById but I'm unsure quite how to make the switch.

I'm also looking for a clickable "Read Less" to be shown once "Read More" is clicked, with "Read Less" returning the text back to the truncated state, with "Read More" then being visible once again and so on.

In summary I'm asking for assistance to:

  1. Switch .getElementById to .getElementsByClassName
  2. Add "Read Less" to show post "Read More" click.

Thanks for taking the time to read this - sorry if I've been unintentionally unclear in anyway. If so please let me know and I'll try to explain further.

like image 564
f484126 Avatar asked Mar 17 '23 09:03

f484126


1 Answers

So, some people's immediate reaction to this would probably be "go to jquery so you can easily query parents, siblings, etc, blah blah blah". I've resisted and done it in pure JS (it was fun).

I've altered two major things:

  1. I've stored your hidden text in a hidden paragraph underneath the parent paragraph tag. This is so we don't have to have some global JS variable holding your hidden text; I'd rather store things like this on the DOM. Like this:

    <span id="parent1">Some text<span class="hidden">Hidden overflow text</span></span>
    
  2. I've given the relevant anchor tags and hidden paragraph tags related to each other corresponding IDs. So you'll have shrinkMe, shrinkMeOverflow, shrinkMeMoreLink, shrinkMeLessLink. This makes it easier to group related things. This may be a consideration for render-time, but for this example and preserving your original code, I've done it by replacing the innerHtml. You'll see that in this loop:

    for (var i = 0; i < shrinkables.length; i++){
        var fullText = shrinkables[i].innerHTML;
        if(fullText.length > len){
            var trunc = fullText.substring(0, len).replace(/\w+$/, '');
            var remainder = "";
            var id = shrinkables[i].id;
            remainder = fullText.substring(len, fullText.length);
            shrinkables[i].innerHTML = '<span>' + trunc + '<span class="hidden" id="' + id + 'Overflow">'+ remainder +'</span></span>&nbsp;<a id="' + id + 'MoreLink" href="#!" onclick="showMore(\''+ id + '\');">More</a><a class="hidden" href="#!" id="' + id + 'LessLink" onclick="showLess(\''+ id + '\');">Less</a>';
        }
    }
    

Here's the full fiddle: http://jsfiddle.net/oxfb3wjs/3/

Let me know if you have any questions. Hope I helped!

Edit: Also, you'll see in the fiddle that I did use getElementsByClassName like you wanted to. I forgot to touch on that, but it's as simple as looping through the returned elements. (see fiddle)

like image 73
wholevinski Avatar answered Apr 02 '23 20:04

wholevinski