Resurgent Resurgent - 1 month ago 14
jQuery Question

jQuery, textarea resize

So I have the standard textarea autogrow code below, which I've changed to bind on input propertychange so as to capture pastes.

(function($)
{
$.fn.autogrow = function(options)
{
return this.filter('textarea').each(function()
{
var self = this;
var $self = $(self);
var minHeight = $self.height();
var noFlickerPad = $self.hasClass('autogrow-short') ? 0 : parseInt($self.css('lineHeight')) || 0;
var settings = $.extend({
preGrowCallback: null,
postGrowCallback: null
}, options );

var shadow = $('<div></div>').css({
position: 'absolute',
top: -10000,
left: -10000,
width: $self.width(),
fontSize: $self.css('fontSize'),
fontFamily: $self.css('fontFamily'),
fontWeight: $self.css('fontWeight'),
lineHeight: $self.css('lineHeight'),
resize: 'none',
'word-wrap': 'break-word'
}).appendTo(document.body);

$self.bind('input propertychange', function()
{
var times = function(string, number)
{
for (var i=0, r=''; i<number; i++) r += string;
return r;
};

var val = self.value.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\n$/, '<br/>&#xa0;')
.replace(/\n/g, '<br/>')
.replace(/ {2,}/g, function(space){ return times('&#xa0;', space.length - 1) + ' ' });

// Did enter get pressed? Resize in this keydown event so that the flicker doesn't occur.
if (event && event.data && event.data.event === 'keydown' && event.keyCode === 13) {
val += '<br />';
}

shadow.css('width', $self.width());
shadow.html(val + (noFlickerPad === 0 ? '...' : '')); // Append '...' to resize pre-emptively.

var newHeight=Math.max(shadow.height() + noFlickerPad, minHeight);
if(settings.preGrowCallback!=null){
newHeight=settings.preGrowCallback($self,shadow,newHeight,minHeight);
}

$self.height(newHeight);

if(settings.postGrowCallback!=null){
settings.postGrowCallback($self);
}
});
});
};
})(jQuery);


I've been trying to get the textarea on initialisation to be the same height as the text. I've seen people use all sorts, e.g.

$(this).height(0).height(this.scrollHeight);


This doesn't work. The other thing I've down is mimicked a keydown event to the textarea, that expands the textarea for certain however it ends up with a lot of whitespace after the text and far too large.

Any suggestions on how to ensure the textarea fits the text even on initialisation? Thanks.

Answer

Here is a functioning code:-

(function($)
{
    $.fn.autogrow = function(options)
    {
        return this.filter('textarea').each(function()
        {
        this.setAttribute('style', 'height:' + (this.scrollHeight) + 'px;overflow-y:hidden;');
        }).on('input', function () {
          this.style.height = 'auto';
          this.style.height = (this.scrollHeight) + 'px';
        });
    };
})(jQuery);

The problem with scrollHeight not working is the textarea was in a div area that was being made invisible by jQuery on document ready. This gave a scrollHeight undefined.

The answer is to introduce a timeout to address that problem 1 second after load to hide the divs, once the textareas have all been properly resized.

Comments