I've been working on adding a character counter to a TEXTAREA field. There are many, many solutions available online for this task.
"Stop-at-Zero" Solution
The problem I'm having is that practically all solutions terminate user input at 0. That's effective, I guess, but it's not optimal in terms of user-friendliness. For example, if a user pastes text into the TEXTAREA, and the text exceeds the field's limitation, this stop-at-zero solution will abruptly truncate the excess text. The user then has to work to find the missing content and then edit their message, submit a second form, or some other burden.
"Negative Character Count" Solution
Other solutions allow the user to enter all they want. The character counter will go from positive to negative. The problem with these counters is lack of enforcement: They allow users to submit the form even with a negative character count.
Twitter Solution
I think Twitter has it right. They let users input all they want and highlight the excess text with a negative character count (and a colored background, which I don't need to have). They disable the submit button while the count is negative.
My (Incomplete) Solution
Working with third-party code I found through Google, I've devised a character counter that works perfectly in terms of the count. But being somewhat new to JS I haven't been able to code the enforcement part.
Here's my question:
How do I get the code to prevent submission of the form when the counter is a negative number?
HTML
<form action="" method="post">
<div>
<textarea name="comments" id="comments" cols="50" rows="10"></textarea>
</div>
<div>
<input type="submit">
</div>
</form>
CSS
form div {
position: relative;
}
form .counter {
position: absolute;
left: 300px;
bottom: -25px;
font-size: 25px;
font-weight: bold;
color: #ccc;
}
form .warning {color: orange;}
form .exceeded {color: red;}
JavaScript
<script src="/js/jquery.js"></script>
<script>
(function($) {
$.fn.charCount = function(options){
// default configuration properties
var defaults = {
allowed: 100,
warning: 25,
css: 'counter',
counterElement: 'span',
cssWarning: 'warning',
cssExceeded: 'exceeded',
counterText: ''
};
var options = $.extend(defaults, options);
function calculate(obj){
var count = $(obj).val().length;
var available = options.allowed - count;
if(available <= options.warning && available >= 0){
$(obj).next().addClass(options.cssWarning);
} else {
$(obj).next().removeClass(options.cssWarning);
}
if(available < 0){
$(obj).next().addClass(options.cssExceeded);
} else {
$(obj).next().removeClass(options.cssExceeded);
}
$(obj).next().html(options.counterText + available);
};
this.each(function() {
$(this).after('<'+ options.counterElement +' class="' + options.css + '">'+ options.counterText +'</'+ options.counterElement +'>');
calculate(this);
$(this).keyup(function(){calculate(this)});
$(this).change(function(){calculate(this)});
});
};
})(jQuery);
</script>
<script>
$(document).ready(function(){
$("#comments").charCount();
});
</script>