Introduction
This article shows how to create a watermark plugin which can be used on textboxes or text areas. The watermark effect allows the developer to specify some brief instructive text inside the textbox without having to interfere with the use of the textbox.
For example, a search form will contain a textbox for the user to enter their search query; you can use the watermark effect on the textbox so that it always displays ‘Enter search query’ unless the user has already entered something.
I have read several articles on how to achieve this watermark effect and thought it would be a good idea to take that approach and put it in reusable, portable jquery plugin.
Note: This plugin requires jQuery 1.4x.
The plugin pattern
There are a few very scant, very simplified examples of how to author a jQuery plugin. The most popular of which is this: http://docs.jquery.com/Plugins/Authoring from the jQuery doc’s site.
However, the examples there are too simplistic to apply to anything of real complexity in which most developers work in. With a bit of hard work, I have learnt some techniques by reading the source code of Jörn Zaefferer’s (http://bassistance.de/) plugins. In the field of jQuery, he is a master.
Options
This plugin will have two options, both with defaults. They are:
- waterClass – the name of the css class that will apply the visual effects . The default is “watermark”. (greyed text etc.)
- valueAttribute – the attribute to read from the target field element. That value of the attribute is used as the water mark text. Title is the recommended default.
The foundation
We will start by laying out our script foundation on which to build our functionality on.
jQuery(function() {
jQuery.waterMark = {
defaults: {
waterClass: 'watermark',
valueAttribute: 'title'
}
};
});
Appendix 1
What this object stores are defaults and these may be accessed by curious developers like so: jQuery.waterMark.defaults.waterClass. Developers can easily override the defaults if they so desire.
Now, we shall define our initialisation method. This is the method users will actual call to kick things off. The first thing to do is cache the settings and apply any settings were passed in over the top of the defaults:
This is then followed by adding the jQuery.waterMark definition.
jQuery.fn.extend({
waterMark: function(settings) {
settings = jQuery.extend({}, jQuery.waterMark.defaults, settings);
return this.each(function(i, item) {
jQuery.data(item, 'settings', settings);
});
}
});
Appendix 2
When a user calls our plugin (e.g.: $(‘#txt1’).waterMark()) this is what is executed. We call extend to extend a blank object with first the defaults and then what was passed to the plugin, overwriting the defaults if applicable. If what was passed in is null, then the defaults stay unchanged.
Secondly, we call this.each. In this case the keyword ‘this’ is pointing to whatever objects wherein the element set that waterM ark was called on (‘#txt1’ – a single element in this example). For each matched item we cache the settings in ‘data’ cache. We then return
this as it is recommended practice for all public plugin methods to return the matched element set so users can easily chain method calls. (e.g. $(‘#txt1’).waterMark().hide ();)
We’ll be adding to this
loop soon but first we need to define our event handlers. The events we are concerned with are the focus and blur events of the text fields and the submit event of the field’s form.
But just before we do that;
Accessing Settings
We’ll add this handy settings method that allows us to simply and consistently access the field’s settings:
function settings(element) {
return element.data('settings');
}
Appendix 3
The Events
function focus() {
var item = $(this);
if (item.hasClass(settings(item).waterClass)) {
item.val('');
item.removeClass(settings(item).waterClass);
}
}
Appendix 4
When our textbox receives focus, we check if the element currently has the water mark effect applied and if it does we reset the value of the field so the user can begin typing. We also remove the css visual effect for the water mark.
function blur() {
var item = $(this);
if (!item.val().length) {
item.addClass(settings(item).waterClass);
item.val(item.attr(settings(item).valueAttribute));
}
}
Appendix 5
When the user shifts focus away from the textbox, we need to check if they have entered anything. If they have, we do nothing, but if they have not, we need to turn the watermark visual effect back on and set the value of the field back to the water mark message text.
function submit() {
var item = $(this);
if (item.val() == item.attr(settings(item).valueAttribute))
item.val('');
}
Appendix 6
Finally we need to handle what happens when the user submits the form. Currently all our watermarked text fields have default values that we do not want to send back the server. So, when the form submits we need to strip these defaults values out before the form sends the data to the server.
Wiring the events
Okay, let us attach our events now and handle the state of the textboxes when the plugin is first attached. We need to modify the code in Appendix 2. We need to change each loop (actually, technically speaking this is not a loop).
return this.each(function(i, item) {
jQuery.data(item, 'settings', settings);
$(item.form).submit(jQuery.proxy(submit, item));
item = jQuery(item);
if (item.val().length && item.val() != item.attr(settings.valueAttribute))
item.removeClass(settings.waterClass);
else {
item.val(item.attr(settings.valueAttribute));
item.addClass(settings.waterClass);
}
}).focus(focus).blur(blur);
We have just added quite a few lines now. Let us go through them. Firstly, we need to bind to the form’s submit event. To make things a bit simpler in the submit handler method, I do not want the
this keyword to map to the form. I want it to map to the specific form field in question.
This was pretty simple to do already but jQuery 1.4 has introduced the
proxy method (http://api.jquery.com/jQuery.proxy/) which allows you to specify what object the
this keyword references in the target event handler method (simply).
Next, our “if” statement checks what state the text field is currently in. Does it already have a value? Does that value match the water mark text? Depending on the state the plugin will switch on the css style and set the value of the field to the water mark text, otherwise it will remove the style if it is already applied.
At the end of the
each method call, we are chaining on another two event binding methods to catch the focus and blur events.
Using the plugin
Reference the plugin code either as an external script file or an inline script block.
A textbox could be defined like the following:
<input type=”text” title=”Type your text here” id=”txt1″ name=”txt1″ />
You then initialise it like this:
<script>$(function() {$(’#txt1′).waterMark();});</script>
Or if you wish, to specify the css class to use:
<script>$(function() {$(’#txt1′).waterMark({waterClass: ‘customclass’});});</script>
Which is very easy to implement.
I hope you found this article useful and thanks for reading it. The full source code of our plugin can be found below:
//Shivam Technologies
//Author: Sam Critchley
//Watermark - jQuery plugin
jQuery(function() {
jQuery.waterMark = {
defaults: {
waterClass: 'watermark',
valueAttribute: 'title'
}
};
jQuery.fn.extend({
waterMark: function(settings) {
settings = jQuery.extend({}, jQuery.waterMark.defaults, settings);
return this.each(function(i, item) {
jQuery.data(item, 'settings', settings);
$(item.form).submit(jQuery.proxy(submit, item));
item = jQuery(item);
if (item.val().length && item.val() != item.attr(settings.valueAttribute))
item.removeClass(settings.waterClass);
else {
item.val(item.attr(settings.valueAttribute));
item.addClass(settings.waterClass);
}
}).focus(focus).blur(blur);
}
});
function submit() {
var item = $(this);
if (item.val() == item.attr(settings(item).valueAttribute))
item.val('');
}
function focus() {
var item = $(this);
if (item.hasClass(settings(item).waterClass)) {
item.val('');
item.removeClass(settings(item).waterClass);
}
}
function blur() {
var item = $(this);
if (!item.val().length) {
item.addClass(settings(item).waterClass);
item.val(item.attr(settings(item).valueAttribute));
}
}
function settings(element) {
return element.data('settings');
}
});
Tags:
Dotnet Tips,
jQuery Tips,
Software Development