onironauta
onironauta

Reputation: 31

Word count limit for multiple textarea tags

I have this script to limit the words on a textarea but I want to use the same function to a form that contains multiple textarea tags.

What is the best way to reuse this and make an independent word counter and limiter for every textarea tag in the same form?

Thanks a lot in advance.

  var wordLimit = 5;
  var words = 0;
  var jqContainer = $(".my-container");
  var jqElt = $(".my-textarea");

function charLimit()
{
  var words = 0;
  var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
  words = wordmatch?wordmatch.length:0;

  if (words > wordLimit) {
      var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
      var lastChar = jqElt.val()[trimmed.length];
      jqElt.val(trimmed + lastChar);
  }
  $('.word-count', jqContainer).text(words);
  $('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
 }
 
 jqElt.on("keyup", charLimit);
 charLimit();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
  <textarea class="my-textarea"></textarea>
  <span class="words-left"></span> words left
<div>

Upvotes: 0

Views: 293

Answers (4)

syanaputra
syanaputra

Reputation: 590

This is how I will normally do it:

  • Create a function that handles the word count refreshMaxWords()
  • Create a hook that can be tied up with the element <textarea data-max-words="5"></textarea>
(function($) {
    var refreshMaxWords = function ($el) {
        var wordLimit = parseInt($el.data('max-words')) || false,
            wordmatch = $el.val().match(/[^\s]+\s+/g),
            words = wordmatch ? wordmatch.length : 0,
            // You can change how to get the "words-left" div here
            $wordsLeft = $el.parent().find('.words-left');

        if (wordLimit !== false) {
            if (words > wordLimit) {
                var trimmed = $el.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
                var lastChar = $el.val()[trimmed.length];
                $el.val(trimmed + lastChar);
            }
        }

        if ($wordsLeft.length > 0) {
            $wordsLeft.html(Math.max(wordLimit - words, 0));
        }

    };

    $(function () {
        $(document).on('keyup.count-words', '[data-max-words]', function (e) {
            refreshMaxWords($(this));
        });
    });
})(jQuery);

This is with assumption of HTML that looks like the following:

  <div class="form-group">
    <label>Input #1</label>
    <textarea class="form-control" data-max-words="5"></textarea>
    <p class="help-block"><span class="words-left">5</span> words left.</p>
  </div>

  <div class="form-group">
    <label>Input #2</label>
    <textarea class="form-control" data-max-words="10"></textarea>
    <p class="help-block"><span class="words-left">10</span> words left.</p>
  </div>

The benefits of this approach are:

  • Cleaner code structure
  • This can be reused on your other projects.

Notes: You don't really need to wrap the javascript in

(function($) {
    // your code here
})(jQuery);

I like doing it because it ensures that there won't be any conflict by accident.

Upvotes: 0

Vusumzi Belmont
Vusumzi Belmont

Reputation: 86

if you need to use that same implementation you could add an id to each text area you are going to put in the form, then add an attribute for= to the corresponding spans pointing to the corresponding text area like this:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
  <textarea id="textarea-1" class="my-textarea" onkeyup="charLimit(this)"></textarea>
  <span for="textarea-1" class="words-left"></span> words left
  <textarea id="textarea-2" class="my-textarea" onkeyup="charLimit(this)"></textarea>
  <span class="words-left" for="textarea-2"></span> words left
<div>

  var wordLimit = 5;
  var words = 0;
  var jqContainer = $(".my-container");

function charLimit(elem)
{ 
  var elm = $(elem)
 var words = 0;
  var wordmatch = elm.val().match(/[^\s]+\s+/g);
  words = wordmatch?wordmatch.length:0;

  if (words > wordLimit) {
      var trimmed = elm.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
      var lastChar = elm.val()[trimmed.length];
      elm.val(trimmed + lastChar);
  }

  $('.word-count', jqContainer).text(words);
  $('[for='+ elm.attr('id') +']', jqContainer).text(Math.max(wordLimit-words, 0));
 }

Upvotes: 0

F.Igor
F.Igor

Reputation: 4350

You can use a generic function ($this) is the textarea element changed. For relative elements, you can use the function .next(selector) Also you can read parameters from attributes (maxwords for example).

 
  var jqContainer = $(".my-container");
  

function charLimit()
{
  var words = 0;
  var jqElt=$(this);
  var wordLimit = jqElt.attr("maxwords");
  var words = 0;
  var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
  words = wordmatch?wordmatch.length:0;
  if (words > wordLimit) {
      var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
      var lastChar = jqElt.val()[trimmed.length];
      jqElt.val(trimmed + lastChar);
  }
  jqElt.next('.words-left').text(Math.max(wordLimit-words, 0));
 }
 
 $(".my-textarea", jqContainer).on("keyup", charLimit).keyup();
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container">
  <textarea id="text1" class="my-textarea" maxwords="5"></textarea>
  <span class="words-left"></span> words left
  <textarea id="text1" class="my-textarea" maxwords="10"></textarea>
  <span class="words-left"></span> words left
<div>

Upvotes: 1

Soc
Soc

Reputation: 7780

You can wrap your logic up in a function and reuse that function.

See example:

function wordCounter(container, limit) {
  var wordLimit = limit;
  var jqContainer = $(container);
  var jqElt = $("textarea", jqContainer);

  function charLimit()
  {
    var words = 0;
    var wordmatch = jqElt.val().match(/[^\s]+\s+/g);
    words = wordmatch?wordmatch.length:0;

    if (words > wordLimit) {
      var trimmed = jqElt.val().split(/(?=[^\s]\s+)/, wordLimit).join("");
      var lastChar = jqElt.val()[trimmed.length];
      jqElt.val(trimmed + lastChar);
    }
    $('.word-count', jqContainer).text(words);
    $('.words-left', jqContainer).text(Math.max(wordLimit-words, 0));
  }

  jqElt.on("keyup", charLimit);
  charLimit();
}

wordCounter(".my-container1", 5);
wordCounter(".my-container2", 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="my-container1">
  <textarea class="my-textarea"></textarea>
  <span class="words-left"></span> words left
</div>
<div class="my-container2">
  <textarea class="my-textarea"></textarea>
  <span class="words-left"></span> words left
</div>

Note that you had an issue in your example where the div tag wasn't closed.

Upvotes: 0

Related Questions