Tag Archives: plugin

Facebook-Style Expanding Textboxes With jQuery

Characters I was recently asked to create a textbox that would vertically expand depending on how much was written in it. This style of text box can be seen in the Facebook news feed for writing comments under peoples feed items. When I receive this type of request, I usually begin by researching what existing systems and plug-ins are out there, investigate the different approaches people take and then write my own based on which way I think best.

Firstly, a textbox (input type=text) is the wrong element to be using. It cannot be any larger than a single line, so a text area element needs to be used. As a text area element will not automatically expand by itself, the general approach to this problem is to use a hidden ‘staging’ element placed way off the viewable screen. The text entered into the text area is copied across to the staging element, which expands as needed and the resulting height used to resize the text area. It is not a difficult thing to achieve with jQuery and the basic structure of the plug-in can be made in relatively few lines of code.

There are a few things to watch out for however. Firstly, because we are taking the contents of a text area and placing it in a div, we need to watch out for special characters that need encoding before they will render correctly. Primarily the newline character but we also have to watch out for the other special characters that can cause issues. Nothing that cannot be fixed with regular expressions. The other thing that we need to be careful of is the CSS styles that have been applied to the text area. We require that the hidden element perfectly mimic the text area and that the text wraps at the same point. If it does not, we will incorrectly predict when the text area needs to grow. The font size and family, line height and padding need to be copied.

This would normally be the point that I post the code, but after I started writing the plug-in, I stumbled across an existing one that I could just not improve upon and decided to use it in it’s entirety. Its by a guy called Jason Frame and his plug-in can be found on github. For my particular implementation, I added the facility to have watermark text in it by utilising the great plugin over on digital bush and I also added some text parsing requirements that were required for the particular project.

Now for a word of warning. There are some problems with this approach, which I have not managed to solve (and incidentally, nor have Facebook). The text area element renders it’s content slightly differently in every browser. In the hidden element, the text will sit up directly against the edge of the div but in a text area it may not. I suspect this gap also varies from operating system to operating system but as far as I can tell, you cannot eliminate it with styles. The consequence of this is that predicting precisely when the text area needs resizing becomes very difficult. The only thing to do is to accommodate this margin of error. This can be done by making the text area display slightly taller than a single line and to always have an extra line available. That way, if things go slightly off, it is still usable. You can see this problem if you put a significant amount of dummy text into the text area and watch when it expands as you type. Instead of expanding when you reach a new line it happens at a different place. If any one manages to figure out how to completely eliminate this problem I am eager to hear how.

jQuery Plugin Callbacks and Events

I have written a fair few plugins for jQuery for both work and side projects. As any developer should, I am always trying to improve my techniques for creating them so that they are as efficient and maintainable as possible.
Up until recently, my usual technique for callbacks and events would be to include the function in the options that you pass in. For instance, you would setup you plugin as follows:

1
2
3
4
5
6
7
8
9
10
11
(function($) {
    $.fn.myPlugin= function(options) {
        var settings = {
            setting1: 0,
            setting2: ''
        };
        //overload default settings
        if (options) { jQuery.extend(settings, options); }
 
        return this.each(function() {
        .....

This would allow you to pass in any number of settings, including callbacks to utilise at runtime:

1
2
3
4
5
  $('#myselector').myPlugin({ 
        setting1:1234, 
        setting2:'somesetting',
        callback1: function() {}
  });

Yesterday it occurred to me that jQuery had a neat feature that is much better than doing this – custom event binding. jQuery not only allows you to bind the DOM events to elements such as click, focus, keydown etc but because of the way it stores all the bindings, you can bind any number of custom events as well. This means that you can set your events for the plugin as follows:

1
2
3
4
$('#myselector').myPlugin({ 
        setting1:1234, 
        setting2:'somesetting'
}).bind("mycallbackevent", function() {...});

Within your plugin you would need to trigger that event like so:

$(this).trigger("mycallbackevent", [somedata]);

This technique also provides a neater alternative to public functions on your plugin. Say you wanted to initialise the plugin when a link is clicked. I would have previously setup a public function in the plugin to do this:

this.init = function() { .. }

and then run it as follows:

$('a').click(function() { $('pluginselector').get(0).init(); }

With custom events you would setup the event inside the plugin as follows:

$(this).bind('init',function() { .. });

and run as follows:

$('a').click(function() { $('pluginselector').trigger('init'); }

Perhaps I have just been writing plugins incorrectly all this time but that seems much better to me.

Sorting Elements with jQuery

Whilst refactoring a jQuery plugin today, I came across a method that placed a list item into an unordered list at a specific point, so that all the items remained in alphabetic order. This long method seemed completely convoluted and slow to me and I decided that there must be an easier way to keep the list in alphabetical order.

There are existing plugins for sorting elements but I never like to just pile on the 3rd party plugins as that means more javascript files to include in a page. Besides, I was sure it should not be difficult.

It soon occured to me that jQuery has the built-in ability to return the elements as an array, using the .get() method and from there, it was not too long before I had my streamlined code to sort the list element alphabetically:

var mylist = $('ul');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   var compA = $(a).text().toUpperCase();
   var compB = $(b).text().toUpperCase();
   return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });

I utilise the javascript array.sort method to sort the elements in the array and then using the jQuery append() method,  reorder them in the actual list element.