Autosize textarea using prototype? - javascript

I'm currently working on an internal sales application for the company I work for, and I've got a form that allows the user to change the delivery address.
Now I think it would look much nicer, if the textarea I'm using for the main address details would just take up the area of the text in it, and automatically resize if the text was changed.
Any ideas? Gracious !!!
Edit by XeeMez:I've modified the code a little because it was acting a little odd, I changed it to activate on keyup, because it wouldn't take into consideration the character that was just typed.
resizeIt = function( ) {
var str = $( 'iso_address' ).value;
var cols = $( 'iso_address' ).cols;
var linecount = 0;
$A( str.split( "\n" ) ).each( function( l ) {
linecount += 1 + Math.floor( l.length / cols ); // take into account long lines
} )
$( 'iso_address' ).rows = linecount;
};

Here's technique for autosizing a textarea.
Uses pixel height instead of line height: more accurate handling of line wrap if a proportional font is used.
Accepts either ID or element as input
Accepts an optional max height param - useful if you'd rather not let the text area grow beyond a certain size (keep it all on-screen, avoid breaking layout, etc.)
Tested on Firefox 3 and IE6
Code: (plain vanilla Javascript)
function FitToContent(id, maxHeight)
{
var text = id && id.style ? id : document.getElementById(id);
if ( !text )
return;
/* Accounts for rows being deleted, pixel value may need adjusting */
if (text.clientHeight == text.scrollHeight) {
text.style.height = "30px";
}
var adjustedHeight = text.clientHeight;
if ( !maxHeight || maxHeight > adjustedHeight )
{
adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
if ( maxHeight )
adjustedHeight = Math.min(maxHeight, adjustedHeight);
if ( adjustedHeight > text.clientHeight )
text.style.height = adjustedHeight + "px";
}
}
Demo: (uses jQuery, targets on the textarea i'm typing into right now - if you have Firebug installed, paste both samples into the console and test on this page)
$("#post-text").keyup(function()
{
FitToContent(this, document.documentElement.clientHeight)
});

Here is the approach I used.
Call expandTextArea on keyup or keypress.
var minimumTextAreaRows = 10;
function expandTextArea(event) {
var element = event.target;
element.rows = minimumTextAreaRows;
while (element.clientHeight < element.scrollHeight) {
element.rows = element.rows + 1;
}
};
Combine with a css that prevents the scrollbar to avoid it flashing
textarea.noscrollbar {
overflow: hidden;
}
This will also "shrink" to the minimum size you specify. Remove element.rows = minimumTextAreaRows; to make it not shrink.

Related

CSS/JS - Can you treat browser auto line breaks like rows to color them?

I am not quite sure how to put my Question in the right words, but I try to describe what I want to do.
Let's say we have a set of data (eg. numbers) from a database and they need to be output as a list. I put a predefined amount of data-fields in a row (for dekstop systems). Every data is in a SPAN with color/margin/padding styles. (Like table-cells.) After that amount of Spans is reached, a forced line break is given. And with each line break, the background color for all spans in that "row" is altered (odd/even). So far no problem.
However, if now someone checks that page with a Smartphone (or you simple resize your Browser Window), the predefined amount does not fit anmyore. As example, in large resolutions you have 6 Spans side by side, colored odd, than 6 Spans colored even. In a small resolution you maybe only have 3 Spans side by side, however in my design you have still 6 Spans colored odd, so two "rows" with the same background-color before it is altered.
Example HTML Output:
<span class="odd">Number 01</span>
<span class="odd">Number 02</span>
<span class="odd">Number 03</span>
<span class="odd">Number 04</span>
<span class="odd">Number 05</span>
<span class="odd">Number 06</span>
<br/>
<span class="even">Number 07</span>
<span class="even">Number 08</span>
<span class="even">Number 09</span>
<span class="even">Number 10</span>
<span class="even">Number 11</span>
<span class="even">Number 12</span>
<br/>
I have absolutely no idea if it is possile to get to know - maybe through Javascript or CSS, how many spans are displayed in a "row", to automate the odd-even-coloring, make it in a way responsive.
Check my Fiddle to maybe show better what I'm trying to get.
Don't you want to use any css framework? Like Bootstrap or Foundation? I hope that will make your work more easier.
Please go through the link.
https://getbootstrap.com/examples/grid/
It already has the solution for mobile device and medium screen.
I can't think of any way to pull it off with CSS, but here's a javascript solution. Browser support is a little off. Didn't realize you tagged jQuery in your post, but it should work on modern browsers at least:
window.addEventListener('resize', function(){
var cells = document.querySelectorAll('.odd,.even');
var activeClass='even', activeLine = 0;
for(var i = 0, len = cells.length; i < len; i++) {
cells[i].classList.remove('odd');
cells[i].classList.remove('even');
if(activeLine != cells[i].offsetTop + cells[i].offsetHeight) {
activeClass = (activeClass === 'even') ? 'odd' : 'even';
activeLine = cells[i].offsetTop + cells[i].offsetHeight
}
cells[i].classList.add(activeClass);
}
});
/* edit: forgot to dispatch the event.
jQuery makes this so much easier to write
than the monstrosity below. */
var event;
event = document.createEvent("HTMLEvents");
event.initEvent("resize", true, true);
window.dispatchEvent(event);
Demo here: http://jsfiddle.net/xh0o6gvy/1
Edit: Here is the jQuery version that Sunny put together found in a fiddle from the comment below. It's definitely a better way to go than the above code if compatibility with older browser versions is required.
function colorSpans() {
var containers = $('.span_container');
containers.each(function() {
var activeClass = 'even';
var activeLine = 0;
var cells = $(this).children('.odd, .even');
cells.each(function() {
$(this).removeClass('odd even');
var offset = $(this).offset();
var height = $(this).outerHeight();
if(activeLine != offset.top + height) {
activeClass = (activeClass === 'even') ? 'odd' : 'even';
activeLine = offset.top + height;
}
$(this).addClass(activeClass);
});
});
}
$(window).on('resize', function() {
colorSpans();
});
colorSpans();
Thanks everybody for your help and inspirations!
So just to round it up, here is the final function I am now using that works with fixed and variable container sizes and recolors container by container.
function colorSpans() {
var containers = $('.span_container');
containers.each(function() {
var activeClass = 'even';
var activeLine = 0;
var cells = $(this).children('.odd, .even');
cells.each(function() {
$(this).removeClass('odd even');
var offset = $(this).offset();
var height = $(this).outerHeight();
if(activeLine != offset.top + height) {
activeClass = (activeClass === 'even') ? 'odd' : 'even';
activeLine = offset.top + height;
}
$(this).addClass(activeClass);
});
});
}
An here is the fiddle: http://jsfiddle.net/z9db7p0t/1/
You could accomplish this with Javascript or plain CSS depending on the rest of your HTML/CSS.
Are the width of the span elements fixed? What about their parent container? If so, you should know where the breakpoints in your layout exist and easily target the elements via css within the proper media queries.
If the size is dynamic, you could update the classes on the spans by calculating how many spans could fit in a row. This would need to be called each time the page was resized however. Using jQuery:
$(function() {
var container = $('#span-container'),
spans = container.find('span');
$(window).on('resize', function(evt) {
var containerWidth = container.width(),
spanWidth = spans.width();
var howManyPerRow = Math.floor(containerWidth / spanWidth);
//reset rows
spans.removeClass('odd even');
var row = 'odd',
c = 1;
spans.each(function() {
$(this).addClass( row );
if( c % howManyPerRow == 0 ) {
row = (row == 'odd') ? 'even' : 'odd';
}
c++;
});
});
});
You are going to need to remove the <br /> tags for this to work correctly. Also, you should set white-space: nowrap; on the spans IMO.

How to get margin value of a div in plain JavaScript?

I can get height in jQuery with
$(item).outerHeight(true);
but how do I with JS?
I can get the height of the li with
document.getElementById(item).offsetHeight
but i will always get "" when I try margin-top:
document.getElementById(item).style.marginTop
The properties on the style object are only the styles applied directly to the element (e.g., via a style attribute or in code). So .style.marginTop will only have something in it if you have something specifically assigned to that element (not assigned via a style sheet, etc.).
To get the current calculated style of the object, you use either the currentStyle property (Microsoft) or the getComputedStyle function (pretty much everyone else).
Example:
var p = document.getElementById("target");
var style = p.currentStyle || window.getComputedStyle(p);
display("Current marginTop: " + style.marginTop);
Fair warning: What you get back may not be in pixels. For instance, if I run the above on a p element in IE9, I get back "1em".
Live Copy | Source
Also, you can create your own outerHeight for HTML elements. I don't know if it works in IE, but it works in Chrome. Perhaps, you can enhance the code below using currentStyle, suggested in the answer above.
Object.defineProperty(Element.prototype, 'outerHeight', {
'get': function(){
var height = this.clientHeight;
var computedStyle = window.getComputedStyle(this);
height += parseInt(computedStyle.marginTop, 10);
height += parseInt(computedStyle.marginBottom, 10);
height += parseInt(computedStyle.borderTopWidth, 10);
height += parseInt(computedStyle.borderBottomWidth, 10);
return height;
}
});
This piece of code allow you to do something like this:
document.getElementById('foo').outerHeight
According to caniuse.com, getComputedStyle is supported by main browsers (IE, Chrome, Firefox).
I found something very useful on this site when I was searching for an answer on this question. You can check it out at http://www.codingforums.com/javascript-programming/230503-how-get-margin-left-value.html. The part that helped me was the following:
/***
* get live runtime value of an element's css style
* http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element
* note: "styleName" is in CSS form (i.e. 'font-size', not 'fontSize').
***/
var getStyle = function(e, styleName) {
var styleValue = "";
if (document.defaultView && document.defaultView.getComputedStyle) {
styleValue = document.defaultView.getComputedStyle(e, "").getPropertyValue(styleName);
} else if (e.currentStyle) {
styleName = styleName.replace(/\-(\w)/g, function(strMatch, p1) {
return p1.toUpperCase();
});
styleValue = e.currentStyle[styleName];
}
return styleValue;
}
////////////////////////////////////
var e = document.getElementById('yourElement');
var marLeft = getStyle(e, 'margin-left');
console.log(marLeft); // 10px
#yourElement {
margin-left: 10px;
}
<div id="yourElement"></div>
Here is my solution:
Step 1: Select the element
Step 2: Use getComputedStyle and provide the element to it
Step 3: Now access all the properties
const item = document.getElementbyId('your-element-id');
const style= getComputedStyle(item);
const itemTopmargin = style.marginTop;
console.log(itemTopmargin)
It will give you margin with px units like "16px" which you might not want.
You can extract the value using parseInt()
const marginTopNumber = parseInt(itemTopmargin)
console.log(marginTopNumber)
It will give you the numerical value only (without any units).

jQuery: making a textarea slide out when rows are changed?

I have a text area box that expands from 3 to 17 rows when the user enters so many characters as well as on a button click.
SetNewSize(); function is the called via onkeyup and expands the text area when the length becomes greater than 50.
morespace(); function is called via the button.
I would like to slide the box out when this happens, any ideas?
Thanks here is my code:
function SetNewSize(textarea){
if (textarea.value.length > 50)
{
textarea.rows = 17;
}
else
{
textarea.rows = 3;
}}
function morespace(){
var thetxt = document.getElementById('more').value;
var box = document.forms["myForm"]["comment"];
if(box.rows == 3)
{
$("#emailme").fadeOut(800);
box.rows = 17;
document.getElementById('more').innerHTML = "less space?";
}
else
{
$("#emailme").fadeIn(800);
box.rows = 3;
document.getElementById('more').innerHTML = "more space?";
}}
By "slide the box out", I'm guessing you mean animate it. While you may not be able to animate textarea rows in jQuery, you can animate the height of the textarea to give the user more room. For example, you trigger something like this:
$('#comment').animate({'height': '+=40'},200);
This will add 40 pixels of height every time it is triggered and it animates it smoothly. If you want to add a number rows, you could simply calculate how large you want the textarea to become and then animate it to that height.
Here's a JSFiddle link for this action and you may want to check out the jQuery animate API.
Well, the quick answer is use something someone already made: https://github.com/gurglet/jQuery-Textarea-Autoresize-Plugin
But if you want to roll your own, I'll update my reply in a moment with the code you need.
Updated Answer:
Assuming you have this HTML:
<button id="emailme">Email me</button>
<form id="myForm">
<input id="more" name="more" type="text">
<textarea id="comment" name="comment" rows="3">
</textarea>
</form>
You could then use this script:
(function(){
var BIG = 17,
SMALL = 3,
currentSize = SMALL,
changeSize = function(rows) {
var $more = $("#more"),
thetxt = $more.val(),
$box = $("#comment"),
currentRows = $box.prop("rows"),
boxRowHeight = $box.height()/currentRows,
newHeight = rows * boxRowHeight;
if (rows === currentRows) return;
return $box.animate({'height': newHeight }, 500 , "swing", function(){
$more.val((currentRows > rows) ? "more space?" : "less space?");
$box.prop("rows", rows);
currentSize = rows;
}).promise();
},
setNewSize = function(event) {
var $area = $(event.target);
if ($area.val().length > 50 && currentSize === SMALL) {
changeSize(BIG);
currentSize = BIG ;
}
};
$("#comment").bind("keyup", setNewSize);
$("#more").click(function(){
if (currentSize === BIG) {
$.when(changeSize(SMALL)).then(function(){
$("#emailme").fadeIn(800);
});
}else{
$.when(changeSize(BIG)).then(function(){
$("#emailme").fadeOut(800);
});
}
});
}​)();​
JSFiddle Link: http://jsfiddle.net/isochronous/fvtY7/
You could also use jquery's attr() like so:
$('#comment').attr('rows', 17);
Where rows represent the attribute to cahnge and 17 the value to set.
To get the number of rows currently used you use:
var rows = $('#comment').attr('rows');

How to count numbers of line in a textarea

I want to make a dynamic textarea, it should increase in rows as the content increase.
I am using this code:
$("#text_textarea").keyup(function(e) {
//splitting textarea value wrt '\n' to count the number of lines
if ($(this).val().lastIndexOf('\n')!=-1)
var x = $(this).val().split('\n');
$(this).attr( "rows" , x.length+1 );
});
But it fails when user continues to write without giving any new line \n (pressing Enter).
var keyUpTimeout = false; // Required variables for performance
var keyupTimer = 0;
$("#text_textarea").keyup(function(e) {
var cooldownTimeout = 500;
//Set the cooldown time-out. The height check will be executed when the user
// hasn't initiated another keyup event within this time
var ths = this;
function heightCheck(){
keyupTimer = false;
// Reset height, so that the textarea can shrink when necessary
ths.style.height = "";
// Set the height of the textarea
var newheight = this.scrollHeight + 2;
ths.style.height = newheight + "px";
}
if(keyupTimeout){ //Has a cooldown been requested?
clearTimeout(keyupTimer); //This+next line: Refresh cooldown timeout.
keyUpTimer = setTimeout(heightCheck, cooldownTimeout);
return; //Return, to avoid unnecessary calculations
}
// Set a cooldown
keyupTimer = setTimeout(heightCheck, cooldownTimeout);
keyupTimeout = true; //Request a cooldown
});
This piece of script will change the height of the textarea to fit the text inside.
Update
I have added an additional feature: To improve performance (changing the CSS height requires a significant amount of computer power), I have added a cooldown effect: The height check will only be executed when the user hasn't initiated a keyup event for 500 milliseconds (adjust this value to meet your wishes).
read this,
Textarea Height increase
TextAreaExpander (Demo)
autoResize Plugin
JQuery Elastic
You should use the attribute wrap='hard' on your textarea.
I write this code. what about it..
$("#text_textarea").keyup(function(e) {
var textarea_height = Number($(this).css('height').replace("px", ""))+4;
var scroll_height = this.scrollHeight;
if(textarea_height < scroll_height ){
$(this).css('height' ,"");
var x = Number(scroll_height) + 3;
if(x != $(this).height())
$(this).css("height", x+"px");
}
});

Mootools textarea scrollHeight

How can I access the scrollHeight using mootools or some other property that contains the height so I can resize it to make an autogrow textarea?
Mootools offers a variety of Element 'dimension' functions that give you information on the scrollable and absolute element sizes. Full docs available here: http://mootools.net/docs/core/Element/Element.Dimensions
What you want to do is compare the return values of your element's getScrollSize() function to your element's getSize() function - in particular the 'y' member, which represents element and scrollable area height, respectively. Something along the lines of this should work:
var myElement = $('myElement'); // get a reference to your element
var scrollSize = myElement.getScrollSize(); // MooTools-specific function.
var elementSize = myElement.getSize(); // MooTools-specific function.
if (scrollSize.y > elementSize.y) {
// determine whether the scrollable area is greater than the dimensions
// of the element. If so, resize the element to match the scrollable area.
myElement.setStyle('height', scrollSize.y + 'px');
}
David Walsh created an excellent plugin for just this purpose:
http://davidwalsh.name/flext-textrea
Here's a simple method I'm using that expands but also contracts the textarea.
The issue you're always going to have is styling on the textare (padding/border).
The first thing to know is that getSize() will get the size of the textarea from absolute top to the absolute bottom, taking into account padding and borders. However, the actual style height of the text area .getStyle('height').toInt(), is the inside of the text box without padding and border. This is the part you need to be interested in as, when you set your height, it sets that, it doesn't set the full height of the textarea from absolute top to bottom.
Here's a working example, with a textarea that's styled (See Demo)
This will also resize the element correctly if you ran it inside domReady.
function expBox(el){
var e = $(el.id);
if(typeof(e._expBox) == "undefined"){
var v = e.value;
e.value = "";
var ss = e.getScrollSize();
var s = e.getSize();
var h = e.getStyle("height").toInt();
e._expBox = (s.y-h)-(s.y-ss.y);
e.value = v;
}
var k = event.keyCode || event.charCode;
if(k == 8 || k == 46){
e.setStyle("height","auto");
}
var ss = e.getScrollSize();
e.setStyle("height",(ss.y-e._expBox));
}
Demo:
http://jsfiddle.net/greatbigmassive/M6X5j/

Categories