简体   繁体   中英

Javascript textarea word limit

I know that HTML has a maxlength attribute, but I want to limit the number of words typed not characters.

After 10 words the user should be able to move his cursor left & edit the text, but not add any more words.

So how can I stop the cursor?

Any suggestions?

Only javascript please.

(The question isn't totally clear... I'm assuming it means "how do I prevent the user from typing more than ten words in a textarea?")

I think you'll struggle to achieve this. What about Paste, for instance?

Here's an alternative suggestion, which might be appropriate for what you're doing: one way that modern UIs (eg. Twitter) deal with this is to put up a letter count or a word count, which turns red once you've gone past the limit. You then get an error if you try to submit the form. That's much easier to achieve than trying to prevent the user from typing more than ten words in the first place.

This doesn't cover all possible user actions, but I was bored and maybe you'll learn something:

HTML:

<textarea id="input_box"></textarea>

JavaScript:

function check_words(e) {
    var BACKSPACE  = 8;
    var DELETE     = 46;
    var MAX_WORDS  = 10;
    var valid_keys = [BACKSPACE, DELETE];
    var words      = this.value.split(' ');

    if (words.length >= MAX_WORDS && valid_keys.indexOf(e.keyCode) == -1) {
        e.preventDefault();
        words.length = MAX_WORDS;
        this.value = words.join(' ');
    }
}

var textarea = document.getElementById('input_box');
textarea.addEventListener('keydown', check_words);
textarea.addEventListener('keyup', check_words);

Try it on JS Bin: http://jsbin.com/isikim/2/edit

  • If there are 10 words in the textarea and the user presses a key, nothing will happen.
  • If a user tries to copy and paste a big chunk of text, the contents of the textarea will immediately be stripped down to just 10 words.

Actually, I'm not sure it matters that this isn't perfect. Since JavaScript runs on the client, you just need something that will work for a normal user. Malicious users can always screw with your JavaScript; no way around that. As long as you're doing real sanitation on the server, there should be no problem.

HTML5 validation is made for tasks like these:

<input 
  pattern="([\w]+\s?){0,5}" 
  onkeypress="if(!this.validity.valid){this.value=this.value.slice(0,-1);return false;}"/>

if it's to be submitted, you can omit the onkeypress handler, as the form won't submit if something's invalid.

One can use poly-fills to support older browsers with this syntax.

Like @sgroves this answer is just for fun :)

$(document).ready(function(){

  $('textarea').on('keydown', function(e){
    // ignore backspaces
    if(e.keyCode == 8)
      return;

    var that = $(this);
    // we only need to check total words on spacebar (i.e the end of a word)
    if(e.keyCode == 32){
      setTimeout(function(){ // timeout so we get textarea value on keydown
        var string = that.val();
        // remove multiple spaces and trailing space
        string = string.replace(/ +(?= )| $/g,'');
        var words = string.split(' ');
        if(words.length == 10){
          that.val(words.join(' '));
        }
      }, 1);
    }
  });
});

Encountered a similar issue recently... here is my take

See demo below and on codepen.io :

 'use strict'; let WordLimiter = function(el){ el.constraints = { /** * Events to listen to */ eventListeners: [ 'keyup', 'input' ], events: { onWordLimiterCount: new CustomEvent('onWordLimiterCount',{ detail: { value: 0, words: [] } }) }, limit: null, validValue: '', /** * Checks if the * @returns {boolean} */ passed: function(){ return this.wordCount() <= this.getLimit(); }, /** * Check if the element has a valid limit * @returns {boolean} */ hasLimit: function(){ return false !== this.getLimit(); }, getLimit: function(){ this.limit = parseInt( this.element.dataset.wordLimit ); this.limit = isNaN( this.limit ) || this.limit <= 0 ? false : this.limit; return this.limit; }, getWords: function(){ this.words = this.element.value.split(' '); /** * Removes words that are just empty strings */ this.words = this.words.filter(function (el) { return el !== null && el.trim() !== ''; }); return this.words; }, /** * Gets the word count * Also triggers an event that you can hook into * @returns {number} */ wordCount: function(){ this.events.onWordLimiterCount.detail.words = this.getWords(); this.events.onWordLimiterCount.detail.value = this.getWords().length; document.dispatchEvent(this.events.onWordLimiterCount ); return this.events.onWordLimiterCount.detail.value; }, /** * Checks constraints * @returns {boolean} */ verify: function(){ console.clear(); if( !this.constraints.passed() ){ console.info( 'FAILED' ); /** * Prevent any further input */ event.preventDefault(); event.stopPropagation(); /** * Revert back to the last valid input * @type {string} */ this.value = this.constraints.validValue; return false; } console.info( 'PASS' ); this.constraints.validValue = this.value; return true; }, /** * Scope purposes */ element: el, }; if( !el.constraints.hasLimit() ){ console.groupCollapsed( 'TextArea does not have a valid limit' ); console.info( el ); console.groupEnd(); return; } el.constraints.eventListeners.forEach(function(e){ el.addEventListener(e, el.constraints.verify ); }); }; /** * Looks for all textarea elements with the data-word-limit attribute */ document.addEventListener("DOMContentLoaded", function(){ let textAreas = document.querySelectorAll("textarea[data-word-limit]"); textAreas.forEach(function(i){ new WordLimiter(i); }); }, true ); let CodePenDemo = { init: function(){ document.addEventListener( 'onWordLimiterCount', function(e){ document.getElementById('counter').value = e.detail.value; }) }, setWordLimit: function(){ document.getElementById('textarea-limited').setAttribute( 'data-word-limit', event.srcElement.value ); } }; CodePenDemo.init(); 
 <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> <script src="index.js"></script> </head> <body class="bg-light"> <div class="container my-3"> <h2>TextArea with Word Limit</h2> <div class="form-group"> <label for="word-limit">Word Limit</label> <input id="word-limit" type="number" min="1" class="form-control" value="50" onchange="CodePenDemo.setWordLimit();"/> </div> <div class="form-group"> <label for="textarea-limited">TextArea</label> <textarea id="textarea-limited" class="form-control" data-word-limit="50" rows="10" cols="20"></textarea> </div> <div class="form-group"> <label for="counter">Words Count</label> <input type="number" id="counter" class="form-control" /> </div> </div> </body> </html> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM