Auto-adjusting textarea to be the same height as inner-text onkeydown - javascript

I'm trying to auto adjust the height of a textarea onkeydown, but it's only working partially. When you're typing text into the textarea, it auto-adjust the height of the textarea per new line of text, which is what I want. But when you're backspacing the text, it auto-adjust the height of the textarea per character-backspaced when you're on the last 5 characters of every last line. What am I doing wrong?
#textarea {
overflow: hidden;
}
<textarea id = 'textarea' onkeydown = "adjust()"></textarea>
<script>
function adjust() {
document.getElementById("textarea").style.height = document.getElementById("textarea").scrollHeight+'px';
} //end of function adjust()
</script>

Create your textarea:
<textarea id="textarea" onkeyup="InputAdjust(this)"></textarea>
then create a function to do the auto height
<script>
function InputAdjust(o) {
o.style.height = "1px";
o.style.height = (25+o.scrollHeight)+"px";
}
</script>
now its +25px, you can change it.
example: https://jsfiddle.net/urp4nbxf/1/

Try this :
$("#textarea").on("keydown",function(){
if($(this).css("height").replace("px","") < $('#textarea').get(0).scrollHeight - 5)
$(this).css("height",($('#textarea').get(0).scrollHeight-5) + "px");
});
Example : https://jsfiddle.net/DinoMyte/dpx1Ltn2/2/

The code below will work, but you will have to manually count how many characters fit in per row, in the textarea. How many characters fit in per row will depend on the cols of the textarea, and of course the font-size of the text.
#textarea {
overflow: hidden;
}
<textarea id = 'textarea' cols = '7' rows = '1' onkeydown = "adjust()"></textarea>
<script>
function adjust() {
var maxCharactersPerColumn = 9; //You have to manually count how many characters fits in per row
var key = event.keyCode;
if (key == 8 || key == 46) {
var length = document.getElementById("textarea").value.length-2;
} //end of if (key == 8 || key == 46)
else {
var length = document.getElementById("textarea").value.length;
} //end of else !(key == 8 || key == 46)
var rows = Math.floor(length/maxCharactersPerColumn)+1;
document.getElementById("textarea").rows = rows;
} //end of function adjust()
</script>

Related

Simplify jQuery for detecting change of an input's value [duplicate]

This question already has answers here:
How to detect a textbox's content has changed
(15 answers)
Closed 8 years ago.
I am tracking the number of characters typed into a textarea are < 140. I am currently only catching characters on 'keyup' but also want to track if a user copy/paste into the textarea. Any suggestions?
$(function(){
var limitDiv = $("#limit");
var limit = limitDiv.data("limit");
var button = $("input");
$("textarea").on("keyup", function(){
var total = this.value.length;
var diff = limit- total;
var condition = diff < 0 || total === 0;
limitDiv.text(diff).toggleClass("red", condition);
button.prop("disabled", condition);
}).trigger("keyup");
})
There is a paste event in jQuery, though its not used very frequently. It seems to still work as of jQuery 2.1.0.
$("#input").on("paste", function(e){
//code goes here
});
http://jsfiddle.net/gty70qc9/2/
Just add a paste event:
$(function(){
var limitDiv = $("#limit");
var limit = limitDiv.data("limit");
var button = $("input");
$("textarea").on("keyup paste", function(){
var total = this.value.length;
var diff = limit- total;
var condition = diff < 0 || total === 0;
limitDiv.text(diff).toggleClass("red", condition);
button.prop("disabled", condition);
button.value(total);
});
})
textarea {
width: 100%;
height: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
<input type="button" value="Submit">
<div id="limit" data-limit="15"></div>

Max lines textarea

I have found some scripts that limit the lines used in a textarea like this:
$(document).ready(function(){
var lines = 10;
var linesUsed = $('#linesUsed');
var newLines=0;
$('#rev').keydown(function(e) {
newLines = $(this).val().split("\n").length;
linesUsed.text(newLines);
if(e.keyCode == 13 && newLines >= lines) {
linesUsed.css('color', 'red');
return false;
}
else {
linesUsed.css('color', '');
}
});
It works fine when you hit enter and limits it to 10 .But the problem occurs when you type sentences that are so long they automatically go to a new line without the \n and when you copy paste a text, then it fails to limit the lines used.
does anyone know how to fix this.
Important: solution needs to work for a textarea
You could try doing it using this logic:
JS :
var limit = 3; // <---max no of lines you want in textarea
var textarea = document.getElementById("splitLines");
var spaces = textarea.getAttribute("cols");
textarea.onkeyup = function() {
var lines = textarea.value.split("\n");
for (var i = 0; i < lines.length; i++)
{
if (lines[i].length <= spaces) continue;
var j = 0;
var space = spaces;
while (j++ <= spaces)
{
if (lines[i].charAt(j) === " ") space = j;
}
lines[i + 1] = lines[i].substring(space + 1) + (lines[i + 1] || "");
lines[i] = lines[i].substring(0, space);
}
if(lines.length>limit)
{
textarea.style.color = 'red';
setTimeout(function(){
textarea.style.color = '';
},500);
}
textarea.value = lines.slice(0, limit).join("\n");
};
Here is the UPDATED DEMO
Well, I couldn't figure out how to calculate the height of only the text inside a textarea, so I used a contenteditable div instead. Hope you like this solution.
HTML
<div id="container">
<div id="rev" contenteditable="true"></div>
</div>
CSS
#container {
height:100px;
width:300px;
cursor:text;
border:1px solid #000
}
#rev {
line-height:20px;
outline:none
}
JS
$(document).ready(function () {
$('#container').click(function() {
$('#rev').focus();
});
var limit = 3;
var lineHeight = parseInt($('#rev').css('line-height'));
$('#rev').keydown(function (e) {
var totalHeight = parseInt($('#rev').height());
var linesUsed = totalHeight / lineHeight;
if (e.keyCode == 13 && linesUsed >= limit) {
$('#rev').css('color', 'red');
return false;
} else {
$('#rev').css('color', '');
}
});
});
HERE IS A DEMO YOU CAN FIDDLE WITH
MAJOR EDIT
Following the OP pointing out I actually forgot to address the most important, I updated my code. I basically removed the check for the enter key and allowed the delete and backspace keys in case the text goes over the limit as follows. You may have to fiddle around with it a little to make it fit to your exact needs.
$(document).ready(function () {
$('#container').click(function() {
$('#rev').focus();
});
var limit = 3;
var lineHeight = parseInt($('#rev').css('line-height'));
$('#rev').keydown(function (e) {
var totalHeight = parseInt($('#rev').height());
var linesUsed = totalHeight / lineHeight;
if (linesUsed > limit) { // I removed 'e.keyCode == 13 &&' from here
$('#rev').css('color', 'red');
if (e.keyCode != 8 && e.keyCode != 46) return false; // I added this check
} else {
$('#rev').css('color', '');
}
});
// I added the following lines
$('#rev').on('paste', function () {
if (linesUsed > limit) {
$('#rev').css('color', 'red');
if (e.keyCode != 8 && e.keyCode != 46) return false;
} else {
$('#rev').css('color', '');
}
});
});
UPDATED DEMO HERE
It's too much work to try to figure how many lines based on the number characters in each line and the textarea width (does the textarea have wrapping off or not? font size, different letter widths, spaces, etc...). The easiest way is to have two textareas (one visible and one not - height set to 0) with the same width and font styles and check the scroll height of the invisible textarea.
Here is an example http://jsfiddle.net/SKYt4/1/
HTML
<textarea id="visible_textarea"></textarea>
<textarea id="hidden_textarea"></textarea> <!-- hidden by setting the height to 0 -->
<div id="used_lines"></div>
CSS
textarea {line-height:16px; /* line height to calculate number of lines */
width:150px; /* need to match width */}
#hidden_textarea {height:0px;
padding:0px;
border:none;
margin:0px;
opacity:0;}
JavaScript
$('#visible_textarea').keyup(function(){
$('#hidden_textarea').val(this.value);
// checking how many lines
var lns = Math.ceil(document.getElementById('hidden_textarea').scrollHeight / parseInt($('#hidden_textarea').css('line-height')));
if (lns > 10) {
$('#used_lines').css('color', '#ff0000');
}
else {
$('#used_lines').css('color', '');
}
$('#used_lines').html(lns+' lines');
});
$('#visible_textarea').change(function(){
$(this).keyup();
});

limited enter chars and prevent user to type

I want the user to enter a maximum of 5 lines in textarea with a maximum 15 chars in each line. After that user should be able to prevent press any keys except Arrows, Del, Backspace etc.
Here is my function which accepts TextareaId, event and limit of each textarea (I'm having 3 textareas with different char limit), I'm reaching to event.preventDefault(); in code but it still allow user to add more chars
function charCountTextarea(textAreaId,event,limit)
{
var code = (event.keyCode ? event.keyCode : event.which);
var Length = $("#"+textAreaId).val().length;
var t = $("#"+textAreaId)[0];
var AmountLeft = limit - Length;
var lineIndex = t.value.substr(0, t.selectionStart).split("\n").length-1;
var t = $("#"+textAreaId).val().split("\n");
var lineIndex = (t.length)-1
var controlKeys = [8, 46, 37, 38,39,40];
var isControlKey = controlKeys.join(",").match(new RegExp(event.which));
if(lineIndex>4 && t[lineIndex].length>15) {
if(isControlKey) {
return;
}
else {
console.log("prevent");
event.preventDefault();
}
}
if(AmountLeft<0) {
if(isControlKey) {
return;
}
else {
console.log("preve 2");
event.preventDefault();
}
}
}
You can simply do this:
var characters=500 //max characters
$("#MyTextArea").keyup(function(){
if($(this).val().length > characters){
        $(this).val($(this).val().substr(0, characters));
}
});
or in you code, instead
event.preventDefault()
to use:
$(this).val($(this).val().substr(0, characters));
If you don't want to use javascript, you can simply limit with 'maxlength' attribute:
<textarea name="hard" maxlength='45'></textarea>

Find out the 'line' (row) number of the cursor in a textarea

I would like to find out and keep track of the 'line number' (rows) of the cursor in a textarea. (The 'bigger picture' is to parse the text on the line every time a new line is created/modified/selected, if of course the text was not pasted in. This saves parsing the whole text un-necessarily at set intervals.)
There are a couple of posts on StackOverflow however none of them specifically answer my question, most questions are for cursor position in pixels or displaying lines numbers besides the textarea.
My attempt is below, it works fine when starting at line 1 and not leaving the textarea. It fails when clicking out of the textarea and back onto it on a different line. It also fails when pasting text into it because the starting line is not 1.
My JavaScript knowledge is pretty limited.
<html>
<head>
<title>DEVBug</title>
<script type="text/javascript">
var total_lines = 1; // total lines
var current_line = 1; // current line
var old_line_count;
// main editor function
function code(e) {
// declare some needed vars
var keypress_code = e.keyCode; // key press
var editor = document.getElementById('editor'); // the editor textarea
var source_code = editor.value; // contents of the editor
// work out how many lines we have used in total
var lines = source_code.split("\n");
var total_lines = lines.length;
// do stuff on key presses
if (keypress_code == '13') { // Enter
current_line += 1;
} else if (keypress_code == '8') { // Backspace
if (old_line_count > total_lines) { current_line -= 1; }
} else if (keypress_code == '38') { // Up
if (total_lines > 1 && current_line > 1) { current_line -= 1; }
} else if (keypress_code == '40') { // Down
if (total_lines > 1 && current_line < total_lines) { current_line += 1; }
} else {
//document.getElementById('keycodes').innerHTML += keypress_code;
}
// for some reason chrome doesn't enter a newline char on enter
// you have to press enter and then an additional key for \n to appear
// making the total_lines counter lag.
if (total_lines < current_line) { total_lines += 1 };
// putput the data
document.getElementById('total_lines').innerHTML = "Total lines: " + total_lines;
document.getElementById('current_line').innerHTML = "Current line: " + current_line;
// save the old line count for comparison on next run
old_line_count = total_lines;
}
</script>
</head>
<body>
<textarea id="editor" rows="30" cols="100" value="" onkeydown="code(event)"></textarea>
<div id="total_lines"></div>
<div id="current_line"></div>
</body>
</html>
You would want to use selectionStart to do this.
<textarea onkeyup="getLineNumber(this, document.getElementById('lineNo'));" onmouseup="this.onkeyup();"></textarea>
<div id="lineNo"></div>
<script>
function getLineNumber(textarea, indicator) {
indicator.innerHTML = textarea.value.substr(0, textarea.selectionStart).split("\n").length;
}
</script>
This works when you change the cursor position using the mouse as well.
This is tough because of word wrap. It's a very easy thing to count the number of line breaks present, but what happens when the new row is because of word wrap? To solve this problem, it's useful to create a mirror (credit: github.com/jevin). Here's the idea:
Create a mirror of the textarea
Send the content from the beginning of the textarea to the cursor to the mirror
Use the height of the mirror to extract the current row
On JSFiddle
jQuery.fn.trackRows = function() {
return this.each(function() {
var ininitalHeight, currentRow, firstIteration = true;
var createMirror = function(textarea) {
jQuery(textarea).after('<div class="autogrow-textarea-mirror"></div>');
return jQuery(textarea).next('.autogrow-textarea-mirror')[0];
}
var sendContentToMirror = function (textarea) {
mirror.innerHTML = String(textarea.value.substring(0,textarea.selectionStart-1)).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br />') + '.<br/>.';
calculateRowNumber();
}
var growTextarea = function () {
sendContentToMirror(this);
}
var calculateRowNumber = function () {
if(firstIteration){
ininitalHeight = $(mirror).height();
currentHeight = ininitalHeight;
firstIteration = false;
} else {
currentHeight = $(mirror).height();
}
// Assume that textarea.rows = 2 initially
currentRow = currentHeight/(ininitalHeight/2) - 1;
//remove tracker in production
$('.tracker').html('Current row: ' + currentRow);
}
// Create a mirror
var mirror = createMirror(this);
// Style the mirror
mirror.style.display = 'none';
mirror.style.wordWrap = 'break-word';
mirror.style.whiteSpace = 'normal';
mirror.style.padding = jQuery(this).css('padding');
mirror.style.width = jQuery(this).css('width');
mirror.style.fontFamily = jQuery(this).css('font-family');
mirror.style.fontSize = jQuery(this).css('font-size');
mirror.style.lineHeight = jQuery(this).css('line-height');
// Style the textarea
this.style.overflow = "hidden";
this.style.minHeight = this.rows+"em";
var ininitalHeight = $(mirror).height();
// Bind the textarea's event
this.onkeyup = growTextarea;
// Fire the event for text already present
// sendContentToMirror(this);
});
};
$(function(){
$('textarea').trackRows();
});
This worked for me:
function getLineNumber(textarea) {
return textarea.value.substr(0, textarea.selectionStart) // get the substring of the textarea's value up to the cursor position
.split("\n") // split on explicit line breaks
.map((line) => 1 + Math.floor(line.length / textarea.cols)) // count the number of line wraps for each split and add 1 for the explicit line break
.reduce((a, b) => a + b, 0); // add all of these together
};
Inspired by colab's answer as a starting point, this includes the number of word wraps without having to introduce a mirror (as in bradbarbin's answer).
The trick is simply counting how many times the number of columns textarea.cols can divide the length of each segment between explicit line breaks \n.
Note: this starts counting at 1.

Javascript Limit Commas

I have a function that displays a countdown next to a text field for the number of characters in the field (think twitter)
<script language="javascript" type="text/javascript">
function countDown(control, maxLen, counter, typeName) {
var len = control.value.length;
var txt = control.value;
var span = document.getElementById(counter);
span.style.display = '';
span.innerHTML = (maxLen - len);
if (len >= (maxLen - 10)) {
span.style.color = 'red';
} else {
span.style.color = '';
}
}
</script>
And the next field down takes a comma separated value. Example:
tomato, apple, orange, pear
and I'd like to limit that list to 5 things (and 4 separating commas).
How can I make a similar function that counts down for the number of commas in the input.
I got this started, but it's not changing the value in the span.
my Javascript
<script language="javascript" type="text/javascript">
var max = 5;
function commaDown(area,ticker){
// our text in the textarea element
var txt = area.val();
// how many commas we have?
var commas = txt.split(",").length;
var span = document.getElementById(ticker);
//var commas ++;
if(commas > max) {
// grab last comma position
var lastComma = txt.lastIndexOf(",");
// delete all after last comma position
area.val(txt.substring(0, lastComma));
//it was count with + 1, so let's take that down
commas--;
}
if (txt == '') {
commas = 0;
}
// show message
span.innerHTML = (max-commas);
}
</script>
and my html (I think the problem lies here)
<input id="choices" type="text" name="choices" class="text medium" onkeyup="commaDown('choices','limit');"/> <span id="limit">5</span><br/>
Any ideas?
Something like this (assuming you have a text field with id csv)
document.getElementById('csv').onkeydown = function(e){
if (!e) var e = window.event;
var list = this.value.split(',');
if (list.length == 5 && e.keyCode == '188' )
{
// what to do if more than 5 commas(,) are entered
// i put a red border and make it go after 1 second
this.style.borderColor ='red';
var _this = this;
setTimeout(function(){
_this.style.borderColor='';
_this.disabled=false;
},1000);
// return false to forbid the surplus comma to be entered in the field
return false;
}
}
example at http://www.jsfiddle.net/gaby/YEHXf/2/
Updated Answer
You seem to have mixed parts of jQuery in your code and that causes the script to fail
var max = 5;
function commaDown(_area, _ticker){
var area = document.getElementById(_area);
// our text in the textarea element
var txt = area.value;
// how many commas we have?
var commas = txt.split(",").length;
var span = document.getElementById(_ticker);
//var commas ++;
if(commas > max) {
// grab last comma position
var lastComma = txt.lastIndexOf(",");
// delete all after last comma position
area.value = txt.substring(0, lastComma);
//it was count with + 1, so let's take that down
commas--;
}
if (txt == '') {
commas = 0;
}
// show message
span.innerHTML = (max-commas);
}
live example at http://jsfiddle.net/z4KRd/
here is a solution:
test: http://jsbin.com/ulobu3
code: http://jsbin.com/ulobu3/edit
if you never used jsBin before, it is very easy, on the left side you have the javascript code (like if it was in your HTML code, and in your right side you have the html code.
and you just need to add /edit to the end of a jsbin url to edit that code, and save any new revisions to that code.
I added jQuery framework to make the example faster to code.

Categories