I'm trying to highlight only matching text within a string at any point.
I have an input box which filters the results. Originally this worked fine to highlight the FIRST character, but the remit has changed to highlight the text within a string at any position.
Fiddle: Highlight matching text
It filters perfectly as it should, but highlights letters starting at the front, not the matching ones. I tried to use indexOf valThis to sort it out but I was probably doing it wrong.
Any help or pointers would be really appreciated.
$('#box').keyup(function () {
var valThis = this.value.toLowerCase();
var length = this.value.length;
$('.objType').each(function () {
var text = $(this).text(),
textL = text.toLowerCase(),
//n = textL.indexOf(valThis);
var htmlR = '<b>' + text.substr(0, length) + '</b>' + text.substr(length);
if(textL.includes(valThis))
{
$(this).html(htmlR).show()
}
else
{
$(this).hide();
}
});
});
The line
var htmlR = '<b>' + text.substr(0, length) + '</b>' + text.substr(length);
says "take length characters from the beginning of the string." You want to start with the first matching character, so you need to know where that is. So you want String#indexOf, not String#includes.
You also want to save the original text so you can compare against that, not against the text updated by the previous filter operation:
// Grab the original text
$(".objType").each(function() { // ***
$(this).data("original", $(this).text()); // ***
}) // ***
$('#box').keyup(function() {
var valThis = this.value.toLowerCase();
var length = this.value.length;
$('.objType').each(function() {
var text = $(this).data("original"), // ***
textL = text.toLowerCase(),
index = textL.indexOf(valThis); // ***
if (index !== -1) {
var htmlR = text.substr(0, index) + '<b>' + text.substr(index, length) + '</b>' + text.substr(index + length); // ***
$(this).html(htmlR).show()
} else {
$(this).hide();
}
});
});
Updated Fiddle, snippet:
// Grab the original text
$(".objType").each(function() { // ***
$(this).data("original", $(this).text()); // ***
}) // ***
$('#box').keyup(function() {
var valThis = this.value.toLowerCase();
var length = this.value.length;
$('.objType').each(function() {
var text = $(this).data("original"), // ***
textL = text.toLowerCase(),
index = textL.indexOf(valThis); // ***
if (index !== -1) {
var htmlR = text.substr(0, index) + '<b>' + text.substr(index, length) + '</b>' + text.substr(index + length); // ***
$(this).html(htmlR).show()
} else {
$(this).hide();
}
});
});
input[type="text"] {
width: 50%;
font-size: 110%;
margin: 10px;
padding: 5px;
float: left;
clear: left;
}
span {
float: left;
clear: left;
margin: 10px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input placeholder="Filter results" id="box" type="text" />
<span class="objType" id="item1">Accepted Event Relation</span>
<span class="objType" id="item2">Case Status Value</span>
<span class="objType" id="item3">External Data Source</span>
<span class="objType" id="item4">Navigation Link Set</span>
Try this.
It does non-destructive copying
$('#box').keyup(function () {
var valThis = this.value.toLowerCase(),
length = this.value.length;
$('.objType').each(function () {
var text = $(this).text(),
textL = text.toLowerCase(),
textStart = textL.indexOf(valThis),
textEnd = textStart+valThis.length;
//n = textL.indexOf(valThis);
var htmlR = text.substring(0,textStart)+'<b>' + text.substring(textStart,textEnd) + '</b>' + text.substring(textStart+length);
if(textStart!=-1) {
$("#"+this.id+"r").html(htmlR).show()
$(this).hide();
}
else {
$("#"+this.id+"r").empty();
$(this).hide();
}
});
});
input[type="text"] {
width: 50%;
font-size: 110%;
margin:10px;
padding: 5px;
float:left;
clear:left;
}
span{
float:left;
clear:left;
margin:10px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input placeholder="Filter results" id="box" type="text" />
<span class="objType" id="item1">Accepted Event Relation</span><span id="item1r"></span>
<span class="objType" id="item2">Case Status Value</span><span id="item2r"></span>
<span class="objType" id="item3">External Data Source</span><span id="item3r"></span>
<span class="objType" id="item4">Navigation Link Set</span><span id="item4r"></span>
I guess you need to use a combination of indexOf, RegEx and substring to find and highlight the position of the word in each string.
See Fiddle here:
https://jsfiddle.net/sxk7qj40/
$('#box').keyup(function () {
const valThis = this.value;
const length = this.value.length;
$('.objType').each(function () {
const text = $(this).text();
const textL = text.toLowerCase();
const position = textL.indexOf(valThis.toLowerCase());
if (position !== -1) {
const matches = text.substring(position, (valThis.length + position));
const regex = new RegExp(matches, 'ig');
const highlighted = text.replace(regex, `<mark>${matches}</mark>`);
$(this).html(highlighted).show();
} else {
$(this).text(text);
$(this).hide();
}
});
});
You would not want to hardcode your substring position at 0, as this will always begin at the start of the string regardless.
Instead, you need to use indexOf, which will return the starting position. You can then use that in the substring to find the starting point that you want to replace. Note that indexOf will return -1 if not found, hence the if statement.
Where to end though? Well, this will come in as a combination of the start position we already have + the string length you just typed.
NOTE: For my own convenience, I used some es2015 features like const and template literals, but you can't use es2015, simply run it through Babel,
or manually replace these parts with var and string concatenation
respectively.
Hope this makes sense?
e.g. ES5 safe:
$('#box').keyup(function () {
var valThis = this.value;
var length = this.value.length;
$('.objType').each(function () {
var text = $(this).text();
var textL = text.toLowerCase();
var position = textL.indexOf(valThis.toLowerCase());
if (position !== -1) {
var matches = text.substring(position, (valThis.length + position));
var regex = new RegExp(matches, 'ig');
var highlighted = text.replace(regex, '<mark>' + matches + '</mark>');
$(this).html(highlighted).show();
} else {
$(this).text(text);
$(this).hide();
}
});
});
Related
I am trying to make it so one or more specific words is highlighted with a button click.
The word is hard-coded in JavaScript. I also want this highlighted feature to not be case sensitive.
In the below code, the word "agreement" will highlight, but only one word - not multiple words or multiple case types.
The goal is for one button to highlight one or more words and another button to clear the highlight. I am able to do this but only for one instance of the word.
$('#clickpurpleagreement').click(function() {
highlightpurpleagreement('agreement')
});
function highlightpurpleagreement(text) {
console.log($('#inputText').text());
//inputText = document.getElementById("inputText")
var innerHTML = $('#inputText').text();
var index = innerHTML.indexOf(text);
if (index >= 0) {
innerHTML = innerHTML.substring(0, index) + "<span class='highlightpurpleagreementword'>" + innerHTML.substring(index, index + text.length) + "</span>" + innerHTML.substring(index + text.length);
$('#inputText').html(innerHTML);
}
}
$('#clear').click(function() {
clearpurple('agreement')
});
function clearpurple(text) {
console.log($('#inputText').text());
//inputText = document.getElementById("inputText")
var innerHTML = $('#inputText').text();
var index = innerHTML.indexOf(text);
if (index >= 0) {
innerHTML = innerHTML.substring(0, index) + "<span class='clearpurple'>" + innerHTML.substring(index, index + text.length) + "</span>" + innerHTML.substring(index + text.length);
$('#inputText').html(innerHTML);
}
}
.highlightpurpleagreementword {
background-color: #847bba;
}
.clearpurple {
background-color: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div>
<a class="button" id="clear"><strong>Clear Highlight</strong></a>
<a class="button button-purple" id="clickpurpleagreement"><strong>Agreement</strong></a>
</div>
<div class="credits" id="inputText">The agreement, Agreement, or agreement is in review</div>
Instead of indexOf use a Regular Expression to find all occurrences of a substring:
function wordIndexes(text) {
var innerHTML = $('#inputText').text();
var regexp = new RegExp(text, 'igm');
while(match = regexp.exec(innerHTML)) {
console.log(match.index);
}
}
wordIndexes('agreement');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="credits" id="inputText">The agreement, Agreement, or agreement is in review</div>
Edit
You've asked for the full JavaScript that would allow you to hard-code the word that needs to be highlighted:
$('#clickpurpleagreement').click(function() {
highlightpurpleagreement('agreement')
});
function highlightpurpleagreement(text) {
var innerHTML = $('#inputText').text();
var regexp = new RegExp(text, 'igm');
var result = '';
var currentIndex = 0;
while(match = regexp.exec(innerHTML)) {
result += innerHTML.substring(currentIndex, match.index) +
'<span class="highlightpurpleagreementword">' + innerHTML.substring(match.index, match.index + text.length) + '</span>'
currentIndex = match.index + text.length;
}
result += innerHTML.substring(currentIndex);
$('#inputText').html(result)
}
.highlightpurpleagreementword {
background-color: #847bba;
}
.clearpurple {
background-color: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a class="button" id="clear"><strong>Clear Highlight</strong></a>
<a class="button button-purple" id="clickpurpleagreement"><strong>Agreement</strong></a>
</div>
<div class="credits" id="inputText">The agreement, Agreement, or agreement is in review</div>
<div>
<button id="clear"><strong>Clear Highlight</strong></button>
<button id="clickpurpleagreement"><strong>Agreement</strong></button>
</div>
<div class="credits" id="inputText">The agreement, Agreement, or agreement is in review</div>
<script>
var colorChanger = document.getElementById("clickpurpleagreement");
colorChanger.addEventListener("click",function() {
document.getElementById('inputText').style.color = "#847bba";
});
var colorChanger1 = document.getElementById("clear");
colorChanger1.addEventListener("click",function() {
document.getElementById('inputText').style.color = "black";
});
</script>
I'm looking for a pure javascript answer as that reflects my projects scope. jQuery answers will not be marked correct, but are welcomed for future question seekers. Side note: I am also not interested in third party libraries.
I'm trying to get the first position (0) of the current line (current is based of selectionStart the chance the user selects more than 1 line) in a multiline textarea, but translate that to caret index.
What have I tried? Nothing pretty:
for ( i = 0; i < this.selectionStart; i++ ) {
if (this.value.substr(i,1).match(/\r?\n|\r/)) {
lineStartIndx = i + 1
}
}
This is proving to be costly when iterating textareas with huge amounts of lines. My personal usage of this will not be executed every keydown, however, I just used it as an example. Are there any better methods, built in or otherwise to emulate this outcome?
My full example:
var input = document.getElementById("ta");
var output = document.getElementById("output");
let pattern = /\r?\n|\r/;
var lineNum, lineStartIndx;
input.addEventListener("keydown", function(e) {
taHandler(this);
})
input.addEventListener("click", function(e) {
taHandler(this);
})
function taHandler(elem) {
lineNum = getLineNumForSelection(elem);
let caretPos = elem.selectionStart;
lineStartIndx = 0;
for ( i = 0; i < caretPos; i++ ) {
if (elem.value.substr(i,1).match(pattern)) {
lineStartIndx = i + 1
}
}
output.innerHTML = "Selection Start: " + caretPos + " Selection End: " + elem.selectionEnd +
" <br> Line Number: " + lineNum.start +
"<br>Line Start Position: " + lineStartIndx;
}
function getLineNumForSelection(sel) {
return {
'start' : sel.value.substr(0, sel.selectionStart).split(pattern).length,
'end' : sel.value.substr(0,sel.selectionEnd).split(pattern).length
};
}
<textarea id="ta" rows="5" cols="50">
Line one
Line two
Line three
Line four
</textarea>
<hr>
<div id="output"></div>
The method in my copy of the snippet splits the content into lines and uses the .length property instead of a loop so it looks "prettier" but according to time complexity of javascript's .length may not be any faster since there is nothing in the spec that prevents slow browser implementation.
Two side notes about the code, I'd use lineStartIndex, not lineStartIndx without the e. Since lineNum is an array, I'd use lineNumArray or selLineNums or something that is more obvious since variables ending in num are generally integers.
var input = document.getElementById("ta");
var output = document.getElementById("output");
let pattern = /\r?\n|\r/;
var lineNum, lineStartIndx;
input.addEventListener("keydown", function(e) {
taHandler(this);
})
input.addEventListener("click", function(e) {
taHandler(this);
})
function taHandler(elem) {
lineNum = getLineNumForSelection(elem);
let caretPos = elem.selectionStart;
lineStartIndx = 0;
// begin modified code
let lines = elem.value.split(pattern),
lineIndex = 0;
while ( (lineIndex + 1 ) < lineNum.start ) {
lineStartIndx += parseInt( lines[lineIndex].length ) + 1;
lineIndex++;
}
// end modified code
// begin replaced code
for ( i = 0; i < caretPos; i++ ) {
if (elem.value.substr(i,1).match(pattern)) {
lineStartIndx = i + 1
}
}
// end replaced code
output.innerHTML = "Selection Start: " + caretPos + " Selection End: " + elem.selectionEnd +
" <br> Line Number: " + lineNum.start +
"<br>Line Start Position: " + lineStartIndx;
}
function getLineNumForSelection(sel) {
return {
'start' : sel.value.substr(0, sel.selectionStart).split(pattern).length,
'end' : sel.value.substr(0,sel.selectionEnd).split(pattern).length
};
}
<textarea id="ta" rows="5" cols="50">
Line one
Line two
Line three
Line four
</textarea>
<hr>
<div id="output"></div>
I have two fields - an input of type "text" and a textarea.
If the input contains the word "dog" and the textarea contains the word "underdog", the "dog" in the textarea should be marked in red in the div with the id "rslt".
How can I achieve this with jQuery?
You can use indexOf to get the position of the current word in a string then apply some css there. This code handles multiple word highlighting.
function markText(text, word, index) {
if (index != -1) {
var left = text.substr(0, index);
var current = word;
var right = text.substr(index + word.length);
var current = '<span style="background-color: red">' + current + '</span>';
text = left + current + right;
if (right.indexOf(word) >= 0) {
text = markText(text, word, (left + current).length + right.indexOf(word));
}
}
return text;
}
$('#btn').click(function () {
if (($('#txtarea').val() == "") || ($('#bx').val() == "")) {
$('#rslt').html('Please fill both boxes!');
return;
}
var words = $('#bx').val().split(' ');
var text = $('#txtarea').val();
words.forEach(function (word) {
if (text.indexOf(word) >= 0) {
text = markText(text, word, text.indexOf(word));
}
});
$("#rslt").html(text); //WHAT HERE?
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Write here:</p>
<input type="text" id="bx"/><br/>
<p>and here:</p>
<textarea cols="100" rows="8" id="txtarea"></textarea><br/>
<button id="btn">GO</button>
<hr/>
<div id="rslt"></div>
<div id="wrapper">
<div>if(true)<span class="openParen bm1">{</span></div>
<div>cout<<"hey";cin>>x;</div>
<div><span class="closeParen bm1>}</span></div>
</div>
I wanted to find cout using regex, something like /cout[^;]*;/ and then wrap it with a span.
<div id="wrapper">
<div>if(true)<span class="openParen bm1">{</span></div>
<div><span id="group">cout<<"hey";</span>cin>>x;</div>
<div><span class="closeParen bm1>}</span></div>
</div>
How will i find the regex occurence and the wrap it with a span? Anyone please?
UPDATE: I inserted cin>>x; after cout, cin shouldn't be wrapped.
I want to use something like this
text.replace(/(cout[^;]*;)/g, '<span class="group">$1</span>');
But i dont know how to apply it in DOM. anyone?
BUG for cin>> and cout<<, they cant be wrap until ; http://jsfiddle.net/3N4AE/11/
This is how you would apply the regex to your DOM using jQuery:
$('#wrapper div').filter(':contains("cout")').each(function () {
$(this).html($(this).text().replace(/(cout[^;]*;)/g, '<span class="group">$1</span>'));
});
Demo fiddle
update Regex way
DEMO
$('#wrapper div').filter(':contains("cout")').each(function () {
var x = $(this);
var txt = x.text();
x.html(txt.replace(/(cout[^;]*;)/g, '<span class="group">$1</span>'));
});
DEMO
var x =$('#wrapper div').filter(':contains("cout")');
var txt = x.text();
x.text('').append('<span id="group">'+txt+'</span>');
updated after OP updated question
DEMO
var x = $('#wrapper div').filter(':contains("cout")');
var txt = x.text();
x.text('');
var cout = txt.split(';');
$.each(cout, function (i, val) {
if (val.indexOf('cout') > -1) {
x.append('<span class="group">' + val + ';</span>');
} else {
x.append(val + ';');
}
});
update
DEMO
$('#wrapper div').filter(':contains("cout")').each(function () {
var x = $(this);
var txt = x.text();
x.text('');
var cout = txt.split(';');
$.each(cout, function (i, val) {
if (val.indexOf('cout') > -1) {
x.append('<span class="group">' + val + ';</span>');
} else {
x.append(val + ';');
}
});
});
updated after koala-dev comment
DEMO
$('#wrapper div').filter(':contains("cout")').each(function () {
var x = $(this);
var txt = x.text();
x.text('');
var cout = txt.split(';');
$.each(cout, function (i, val) {
if (val.indexOf('cout') > -1) {
x.append('<span class="group">' + val + ';</span>');
} else if ($.trim(val) != '') {
x.append(val + ';');
}
});
});
This should help
var pattern = /cout[^;]*;/;
var txt = $('#wrapper').find('div:nth-child(2)').text();
var el = $('#wrapper').find('div:nth-child(2)');
$(el).text("").append('<span id="group">' + txt + '</span');
jsfiddle
I am developing a character count for my textarea on this website. Right now, it says NaN because it seems to not find the length of how many characters are in the field, which at the beginning is 0, so the number should be 500. In the console in chrome developer tools, no error occur. All of my code is on the site, I even tried to use jQuery an regular JavaScript for the character count for the textarea field, but nothing seems to work.
Please tell me what I am doing wrong in both the jQuery and the JavaScript code I have in my contact.js file.
$(document).ready(function() {
var tel1 = document.forms["form"].elements.tel1;
var tel2 = document.forms["form"].elements.tel2;
var textarea = document.forms["form"].elements.textarea;
var clock = document.getElementById("clock");
var count = document.getElementById("count");
tel1.addEventListener("keyup", function (e){
checkTel(tel1.value, tel2);
});
tel2.addEventListener("keyup", function (e){
checkTel(tel2.value, tel3);
});
/*$("#textarea").keyup(function(){
var length = textarea.length;
console.log(length);
var charactersLeft = 500 - length;
console.log(charactersLeft);
count.innerHTML = "Characters left: " + charactersLeft;
console.log("Characters left: " + charactersLeft);
});​*/
textarea.addEventListener("keypress", textareaLengthCheck(textarea), false);
});
function checkTel(input, nextField) {
if (input.length == 3) {
nextField.focus();
} else if (input.length > 0) {
clock.style.display = "block";
}
}
function textareaLengthCheck(textarea) {
var length = textarea.length;
var charactersLeft = 500 - length;
count.innerHTML = "Characters left: " + charactersLeft;
}
$("#textarea").keyup(function(){
$("#count").text($(this).val().length);
});
The above will do what you want. If you want to do a count down then change it to this:
$("#textarea").keyup(function(){
$("#count").text("Characters left: " + (500 - $(this).val().length));
});
Alternatively, you can accomplish the same thing without jQuery using the following code. (Thanks #Niet)
document.getElementById('textarea').onkeyup = function () {
document.getElementById('count').innerHTML = "Characters left: " + (500 - this.value.length);
};
⚠️ The accepted solution is outdated.
Here are two scenarios where the keyup event will not get fired:
The user drags text into the textarea.
The user copy-paste text in the textarea with a right click (contextual menu).
Use the HTML5 input event instead for a more robust solution:
<textarea maxlength='140'></textarea>
JavaScript (demo):
const textarea = document.querySelector("textarea");
textarea.addEventListener("input", event => {
const target = event.currentTarget;
const maxLength = target.getAttribute("maxlength");
const currentLength = target.value.length;
if (currentLength >= maxLength) {
return console.log("You have reached the maximum number of characters.");
}
console.log(`${maxLength - currentLength} chars left`);
});
And if you absolutely want to use jQuery:
$('textarea').on("input", function(){
var maxlength = $(this).attr("maxlength");
var currentLength = $(this).val().length;
if( currentLength >= maxlength ){
console.log("You have reached the maximum number of characters.");
}else{
console.log(maxlength - currentLength + " chars left");
}
});
textarea.addEventListener("keypress", textareaLengthCheck(textarea), false);
You are calling textareaLengthCheck and then assigning its return value to the event listener. This is why it doesn't update or do anything after loading. Try this:
textarea.addEventListener("keypress",textareaLengthCheck,false);
Aside from that:
var length = textarea.length;
textarea is the actual textarea, not the value. Try this instead:
var length = textarea.value.length;
Combined with the previous suggestion, your function should be:
function textareaLengthCheck() {
var length = this.value.length;
// rest of code
};
Here is simple code. Hope it help you
$(document).ready(function() {
var text_max = 99;
$('#textarea_feedback').html(text_max + ' characters remaining');
$('#textarea').keyup(function() {
var text_length = $('#textarea').val().length;
var text_remaining = text_max - text_length;
$('#textarea_feedback').html(text_remaining + ' characters remaining');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="textarea" rows="8" cols="30" maxlength="99" ></textarea>
<div id="textarea_feedback"></div>
This code gets the maximum value from the maxlength attribute of the textarea and decreases the value as the user types.
<DEMO>
var el_t = document.getElementById('textarea');
var length = el_t.getAttribute("maxlength");
var el_c = document.getElementById('count');
el_c.innerHTML = length;
el_t.onkeyup = function () {
document.getElementById('count').innerHTML = (length - this.value.length);
};
<textarea id="textarea" name="text"
maxlength="500"></textarea>
<span id="count"></span>
I found that the accepted answer didn't exactly work with textareas for reasons noted in Chrome counts characters wrong in textarea with maxlength attribute because of newline and carriage return characters, which is important if you need to know how much space would be taken up when storing the information in a database. Also, the use of keyup is depreciated because of drag-and-drop and pasting text from the clipboard, which is why I used the input and propertychange events. The following takes newline characters into account and accurately calculates the length of a textarea.
$(function() {
$("#myTextArea").on("input propertychange", function(event) {
var curlen = $(this).val().replace(/\r(?!\n)|\n(?!\r)/g, "\r\n").length;
$("#counter").html(curlen);
});
});
$("#counter").text($("#myTextArea").val().replace(/\r(?!\n)|\n(?!\r)/g, "\r\n").length);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<textarea id="myTextArea"></textarea><br>
Size: <span id="counter" />
For those wanting a simple solution without jQuery, here's a way.
textarea and message container to put in your form:
<textarea onKeyUp="count_it()" id="text" name="text"></textarea>
Length <span id="counter"></span>
JavaScript:
<script>
function count_it() {
document.getElementById('counter').innerHTML = document.getElementById('text').value.length;
}
count_it();
</script>
The script counts the characters initially and then for every keystroke and puts the number in the counter span.
Martin
They say IE has issues with the input event but other than that, the solution is rather straightforward.
ta = document.querySelector("textarea");
count = document.querySelector("label");
ta.addEventListener("input", function (e) {
count.innerHTML = this.value.length;
});
<textarea id="my-textarea" rows="4" cols="50" maxlength="10">
</textarea>
<label for="my-textarea"></label>
var maxchar = 10;
$('#message').after('<span id="count" class="counter"></span>');
$('#count').html(maxchar+' of '+maxchar);
$('#message').attr('maxlength', maxchar);
$('#message').parent().addClass('wrap-text');
$('#message').on("keydown", function(e){
var len = $('#message').val().length;
if (len >= maxchar && e.keyCode != 8)
e.preventDefault();
else if(len <= maxchar && e.keyCode == 8){
if(len <= maxchar && len != 0)
$('#count').html(maxchar+' of '+(maxchar - len +1));
else if(len == 0)
$('#count').html(maxchar+' of '+(maxchar - len));
}else
$('#count').html(maxchar+' of '+(maxchar - len-1));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="message" name="text"></textarea>
$(document).ready(function(){
$('#characterLeft').text('140 characters left');
$('#message').keydown(function () {
var max = 140;
var len = $(this).val().length;
if (len >= max) {
$('#characterLeft').text('You have reached the limit');
$('#characterLeft').addClass('red');
$('#btnSubmit').addClass('disabled');
}
else {
var ch = max - len;
$('#characterLeft').text(ch + ' characters left');
$('#btnSubmit').removeClass('disabled');
$('#characterLeft').removeClass('red');
}
});
});
This solution will respond to keyboard and mouse events, and apply to initial text.
$(document).ready(function () {
$('textarea').bind('input propertychange', function () {
atualizaTextoContador($(this));
});
$('textarea').each(function () {
atualizaTextoContador($(this));
});
});
function atualizaTextoContador(textarea) {
var spanContador = textarea.next('span.contador');
var maxlength = textarea.attr('maxlength');
if (!spanContador || !maxlength)
return;
var numCaracteres = textarea.val().length;
spanContador.html(numCaracteres + ' / ' + maxlength);
}
span.contador {
display: block;
margin-top: -20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea maxlength="100" rows="4">initial text</textarea>
<span class="contador"></span>