Introduction
This article presents a watermarked auto-complete jQuery plugin.
Background
The watermarked auto-complete jQuery plugin is built upon the "jQuery UI" auto-complete. It adds a watermark to the original plugin and offers the ability to limit the user's capability to enter free text into the text box. In this article, I will present this plugin and a small demo application on how to use it.
Bug Fixes: Since the first release of this article, some friends have pointed out some bugs related to this plugin. They are the following:
- The watermark text has a wrong capitalization.
- The method name "distory" should be "destroy".
- There is a functonal bug during the initialization of the plugin. The typos in the code prevent the users of the plugin to subscribe to the "select" event of the "jQuery UI" auto-complete.
These bugs have been fixed and I have uploaded the plugin in the "jquery-watermarkAutocomplete-1.0.1.zip" file. You can still download the "Watermarkautocomplete" solution to run the demo. The demo application does not touch the bugs in the plugin and should run smoothly without the bug fixes. Just remember to use the version in the "jquery-watermarkAutocomplete-1.0.1.zip" if you want to use this plugin as it is in your own application. Thanks to the friends who found the bugs.
The Visual Studio 2010 solution is the demo application.
- The "jquery-watermarkAutocomplete-1.0.0.js" in the "Scripts" folder is the watermarked auto-complete plugin.
- The "Default.htm" is the web page to demonstrate how to use the plugin.
This article assumes that the readers have some basic knowledge on "jQuery". Since the data displayed in the auto-complete text box in the example comes from an "MVC" controller, you will need to have some basic knowledge on "MVC" as well.
I will first present the plugin and then show you how to use it.
The Watermarked Auto-complete Plugin
The watermarked auto-complete plugin is implemented in the "jquery-watermarkAutocomplete-1.0.0.js" file:
(function ($) {
var methods = {
init: function (options) {
var settings = {
watermarkstyle: { "color": "grey", "font-style": "italic" },
watermarktext: "Please Enter some text",
autocompletesource: null,
autocompleteselect: null,
autocompletechange: null,
allowfreetext: false,
watermarkenabled: true
}
return this.each(function () {
if (options) {
var $this = $(this);
$.extend(settings, options);
if (!settings.regulartextstyle) {
var regulartextstyle = {
"color": $this.css("color"),
"font-style": $this.css("font-style")
}
settings.regulartextstyle = regulartextstyle;
}
settings.watermarktext = $.trim(settings.watermarktext);
var instancedata = { options: $.extend({}, settings), data: {} };
$this.data("watermarkAutocomplete", instancedata);
if (instancedata.options.autocompletesource) {
$(this).autocomplete({
source: instancedata.options.autocompletesource,
select: function (event, ui) {
if (instancedata.options.autocompleteselection) {
instancedata.options.autocompleteselection(event, ui);
}
instancedata.data.autocompleteselection = ui.item;
},
change: function (event, ui) {
var $this = $(this);
if (instancedata.options.autocompletechange) {
instancedata.options.autocompletechange(event, ui);
}
if (!instancedata.options.allowfreetext) {
clearfreetext($this, instancedata.options,
instancedata.data);
}
}
});
}
$this.bind("keyup.watermarkAutocomplete", function () {
var instancedata = $(this).data("watermarkAutocomplete");
instancedata.data.autocompleteselection = null;
});
$this.bind("focus.watermarkAutocomplete", function () {
var $this = $(this);
var instancedata = $this.data("watermarkAutocomplete");
if (instancedata.options.watermarkenabled) {
clearwatermark($this, instancedata.options);
}
});
$this.bind("blur.watermarkAutocomplete", function () {
var $this = $(this);
var instancedata = $this.data("watermarkAutocomplete");
if (instancedata.options.watermarkenabled) {
applywatermark($this, instancedata.options);
}
})
if (instancedata.options.watermarkenabled) {
applywatermark($this, instancedata.options);
}
}
});
},
enablewatermark: function (enable) {
return this.each(function () {
var $this = $(this);
var instancedata = $this.data("watermarkAutocomplete");
instancedata.options.watermarkenabled = enable;
if (enable) {
applywatermark($this, instancedata.options);
}
else {
clearwatermark($this, instancedata.options);
}
});
},
allowfreetext: function (allow) {
return this.each(function () {
var $this = $(this);
var instancedata = $this.data("watermarkAutocomplete");
instancedata.options.allowfreetext = allow;
if (!instancedata.options.allowfreetext) {
clearfreetext($this, instancedata.options, instancedata.data);
}
});
},
destroy: function () {
return this.each(function () {
var $this = $(this);
var instancedata = $this.data("watermarkAutocomplete");
clearwatermark($this, instancedata.options);
$this.removeData("watermarkAutocomplete");
$this.unbind(".watermarkAutocomplete");
$this.autocomplete("destroy");
});
}
};
$.fn.watermarkAutocomplete = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === "object" || !method) {
return methods.init.apply(this, arguments);
} else {
$.error("Method " + method + "does not exist on jQuery.watermarkAutocomplete");
}
};
var applywatermark = function ($this, options) {
var text = $.trim($this.val());
if ((text == "") || (text == options.watermarktext)) {
$this.css(options.watermarkstyle);
$this.val(options.watermarktext);
}
};
var clearwatermark = function ($this, options) {
var text = $.trim($this.val());
if (text == options.watermarktext) {
$this.val("");
}
$this.css(options.regulartextstyle);
};
var clearfreetext = function ($this, options, data) {
if (!data.autocompleteselection) {
$this.val("");
if (options.watermarkenabled) {
applywatermark($this, options);
}
}
};
})(jQuery);
This article is not intended to show you how to write "jQuery" plugins. If you are interested in writing a plugin, you can refer to the "Official plugin authoring guidelines". To use this plugin though, we can use the following options to configure the text box:
- Property "
watermarkenabled
" - true
/false
. We can use this option to control if the watermark text should be displayed when the text box is empty. The default is "true
". - Property "
allowfreetext
" - true
/false
. We can use this option to control if the auto-complete text box allows free text. The default is "false
". - Property "
watermarkstyle
" - the CSS style when the auto-complete box is watermarked. The default is ""{ "color": "grey", "font-style": "italic" }"
. - Property "
watermarktext
" - the watermark text. The default text is "Please enter some text
". - Function "
autocompletesource
" - A function called when the user types in some text into the auto-complete box. It should provide a list of that matches the user input. - Function "
autocompleteselect
" - A function called when an item is selected from the auto-complete list. - Function "
autocompletechange
" - A function called when the auto-complete box looses focus if the text in the auto-complete box is changed.
When initiating the auto-complete box, if the "autocompletesource
" function is not provided in the options, the text box will behave as a watermarked text box. Besides the options, this plugin also provides the following methods to allow you to change the behavior of the auto-complete box after it is initialized. According to the "Official plugin authoring guidelines", these methods should be called with the following syntax:
- Method "
enablewatermark
". It should be called like "$(selector).watermarkAutocomplete('enablewatermark', true/false)
". It is used to change if we want to show the watermark text when the text box is empty. - Method "
allowfreetext
". It should be called like "$(selector).watermarkAutocomplete('allowfreetext', true/false)
". It is used to change if we want to allow free text input to the auto-complete box. - Method "
destroy
". It should be called like "$(selector).watermarkAutocomplete('destroy')
". Calling this method will un-bind the plugin with the text box and free all the resources used.
Now let us take a look at the demo application to see how to use this "jQuery" plugin.
The Data Model of the Demo Application
The data model of this demo application is implemented in the "LanguageRepository.cs" file in the "Models" folder:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Watermarkautocomplete.Models
{
public class Language
{
public int Id { get; set; }
public string Name { get; set; }
}
public static class LanguageRepository
{
public static List<Language> Languages { get; set; }
static LanguageRepository()
{
Languages = new List<Language>();
Languages.Add(new Language { Id = 1, Name = "Basic" });
Languages.Add(new Language { Id = 2, Name = "Fortran" });
Languages.Add(new Language { Id = 3, Name = "Smalltalk" });
Languages.Add(new Language { Id = 4, Name = "Cobal" });
Languages.Add(new Language { Id = 5, Name = "Lisp" });
Languages.Add(new Language { Id = 6, Name = "Prolog" });
Languages.Add(new Language { Id = 7, Name = "Matlab" });
Languages.Add(new Language { Id = 8, Name = "C" });
Languages.Add(new Language { Id = 9, Name = "C++" });
Languages.Add(new Language { Id = 10, Name = "C#" });
Languages.Add(new Language { Id = 11, Name = "Java" });
Languages.Add(new Language { Id = 12, Name = "PHP" });
Languages.Add(new Language { Id = 13, Name = "Python" });
Languages.Add(new Language { Id = 14, Name = "Javascript" });
Languages.Add(new Language { Id = 15, Name = "Ruby" });
}
}
}
The "LanguageRepository
" class defines a list of computer languages. This demo application will show you how to display the languages that match the text in the text box to auto-complete the user entry.
The "Default.htm" Page
The "default.htm" page is the web page that uses the watermarked auto-complete plugin:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Watermark Autocomplete Demo</title>
<link href="Content/redmond/jquery-ui-1.8.14.custom.css"
rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.6.2.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.14.custom.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-watermarkAutocomplete-1.0.0.js"
type="text/javascript"></script>
<script src="Scripts/Default.htm.js" type="text/javascript"></script>
</head>
<body>
<div>
<input type="text" id="txtAutoComplete" style="width: 150px" />
</div>
</body>
</html>
In this example, I will show you how to apply the watermarked auto-complete plugin to the text box "txtAutoComplete
". The watermarked auto-complete plugin is built upon the "jQuery UI". We will need to refer to the following libraries as well as the "jquery-watermarkAutocomplete-1.0.0.js" file in the "Default.htm" file:
The JavaScript code that sets up the watermarked auto-complete effect for the text box "txtAutoComplete
" is implemented in the "Default.htm.js" file.
The "Default.htm.js" script file
The client script for the "Default.htm" page is implemented in the "Default.htm.js" file:
$(document).ready(function () {
var dataSourceUrl = "DataSource/GetData";
var maxResult = 5;
var options = {
autocompletesource: function (request, response) {
var term = $.trim(request.term);
var dataToServer = { searchText: term, maxResults: maxResult };
$.ajax({
url: dataSourceUrl, type: "POST", dataType: "json",
data: dataToServer, success: function (data) {
response($.map(data, function (v) {
var Id = v.Id;
var Name = v.Name;
return { label: Name, value: Name, Id: Id };
}));
}
});
}
};
$("#txtAutoComplete").watermarkAutocomplete(options);
});
Although this plugin offers some more options, this demo application tries to keep it simple by taking advantage of the default options. When I initiate the auto-complete text box, I only provided the "autocompletesource
" function. When the user types some text into the text box, an "Ajax" call is made to the server to bring the matching computer languages.
The MVC Controller "DataSourceController"
The "MVC" controller that receives the "Ajax" call and returns the matching list of the computer languages is implemented in the "DataSourceController.cs" file in the "Controllers" folder:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Watermarkautocomplete.Models;
namespace Watermarkautocomplete.Controllers
{
public class DataSourceController : Controller
{
[HttpPost]
public ActionResult GetData(string searchText, int maxResults)
{
searchText = searchText.ToUpper();
var languages = LanguageRepository.Languages;
var selected = from language in languages
where language.Name.ToUpper()
.StartsWith(searchText)
orderby language.Name
select language;
return Json(selected.Take(maxResults));
}
}
}
We now complete the watermarked auto-complete plugin and the demo application on how to use it. We can test run our application.
Run the Application
When the application launches in the web browser, we see the auto-complete text box. As expected, it is watermarked.
If we type in some text in the text box, the auto-complete plugin issues an "Ajax" call to bring the match list of the computer languages for us to select from. Since we have limited number of languages in our data source, only certain text can bring us a matching language list. In this case, we have both "Java" and "Javascript" that match our input text "j
".
We can then select one of the choices and the text box is auto-completed with our selection.
When we setup the auto-completion, we chose not to allow the user to input free text. We can then type some other text in the text box like "Java A
". Since "Java A
" is not a language in the selection list, when the text box loses focus, the text is cleared and the watermark is shown.
Points of Interest
- This article presented a watermarked auto-complete jQuery plugin.
- I have made my effort to comply with the "Official plugin authoring guidelines" and this plugin should largely fulfill the guidelines. But if you see any places that I need to change, please let me know.
- This plugin is built upon the "jQuery UI" auto-complete plugin. If you feel that you need certain functionalities provided by the "jQuery UI" but not this plugin, you can use the "jQuery UI" plugin directly.
- I hope you like my postings and I hope this article can help you one way or the other.
History
- First revision - 8/17/2011