4

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.

f484126
  • 93
  • 1
  • 1
  • 8

2 Answers2

9

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)

wholevinski
  • 3,658
  • 17
  • 23
  • thank you! I really appreciate that you've taken the time to put this together. I do however have one major issue, and another minor one. Major issue: when "more" or "less" are clicked, the page jumps to the top instead of remaining in it's current position. Minor issue: Would it be possible to have the "more" and "less", when each are visible to appear after the of the last word, instead of on a separate line? e.g sample text "More" – f484126 Apr 17 '15 at 15:53
  • Sure! Gimme a few minutes to make some edits. The major issue is addressed here: http://stackoverflow.com/a/11246131/769971 – wholevinski Apr 17 '15 at 16:02
  • Thank you for your continued efforts and for providing that link, it worked perfectly. – f484126 Apr 17 '15 at 16:04
  • Updated my fiddle and the code samples. The minor issue you mentioned is caused by using the paragraph tag. It renders a newline when you close it. I switched them to be spans and it all appears on the same line now. – wholevinski Apr 17 '15 at 16:06
  • It's nice but it breaks if there is a link where it breaks the paragraph. – Martin James Aug 13 '20 at 20:06
  • This is incorrect and gives me issues with some text. The substring for the remainder should start based on the length of "trunc". – christian Aug 24 '21 at 01:47
  • 1
    Thanks @wholevinski I've fixed some things; I closed a , added a line to support elements without IDs, added an ellipsis and most importantly replaced the whitespace removal, so the substring is extracted correctly. I've made a fiddle: https://jsfiddle.net/ursbraem/6te2sLx4/4/ --- although it's probably not ECS6 and so on, it's a very useful snippet. Should I edit your answer above with the changes? – Urs Aug 18 '22 at 17:37
  • I would go ahead and add an additional answer with your changes @Urs. This answer is pretty old, and since then they've also added an integrated code runner so yours will look nicer :) – wholevinski Aug 18 '22 at 19:00
0

I have tried with simple HTML and Javascript.

Made simple showParagraph function, which renders given string with read more/less support. It supports dynamic length of text. You can set, how many characters you wants to display by default.

showParagraph(targetId, paragraphText, displayLimit);

Here,

paragraphText means text which you wants to load with 'Read More'/'Read less' feature.

targetId means ID of HTML element where you want this text to be loaded.

And displayLimit means how many characters you wants to show by default.

Please have a look at below fiddle: https://jsfiddle.net/yash_mochi/5d72zbsf/7/

Yash Mochi
  • 769
  • 6
  • 15