Posts Tagged ‘jQuery’

Creating a Twitter style character counter with jQuery

Thursday, April 22nd, 2010

I’m not really sure why I decided to write the javascript to handle a text area with a limited character count as well as a character counter like that used on Twitter. Reason or not, it turned out to be fairly simple to pull off. By far the hardest part was finding a way to only run the onkeyup event when the appropriate text area field was focused. The idea being that every time the user presses a key typing in their name there isn’t a bunch of javascript running unnecessarily in the background. Somewhere on the web I found an activeElement javascript method that returns the focused form element. Just a fair warning that I’ve never used this outside of this example and have no idea if it works in IE or not. I did check though in Chrome, Firefox, and Safari however.

I came up with two scenarios for using a limited character text area with a character counter. First is a text area that allows x number of characters. The counter counts up to this number and then increases no more. The string itself is trimmed to the max character on each keypress beyond the max characters allowed. Second is a text area much truer to the Twitter ‘What’s Happening’ text area. This text area will allow the user to type as much as they wish, while the counter begins at the max and counts down to 0. At zero the counter begins counting down through negative numbers. I’ve also added a class at this point that changes the color of negative numbers to red.

Let’s take a look at some code.

The HTML

<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Character Counter</title>

		<!-- JQUERY LINK -->
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>

		<!-- CHARACTER COUNTER JS FILE -->
		<script src="js/character_counter.js" type="text/javascript"></script>
	</head>

	<body>
		<form name="text_input" method="post" action="#">
			<textarea name="my_text" id="my_text" cols="50" rows="10"></textarea>
		</form>

		Characters: <em><span id="counter"></span></em>
	</body>
</html>

Pretty simple stuff we have here. First is a link to the jQuery library hosted by Google. Next is a link to the character_counter.js file that I will get into next. As far as HTML is concerned we have a text area with an id of ‘my_text’ and a span with an id of ‘counter’. The span is empty because it will serve as a container for us to dynamically insert the character count as the user types into the text area.

I will list first the javascript that counts up to the max number of characters and then trims the string to the max character count so that the user can literally on enter the allowed number of characters. Afterwards, I will show the code that will allow the user to type as much as they wish and count into negative numbers.

character_counter.js (Counts up with character limit)

$(document).ready(function()
{
	var max_length = 10;

	//run listen key press
	whenkeydown(max_length);
});

whenkeydown = function(max_length)
{
	$("#my_text").unbind().keyup(function()
	{
		//check if the appropriate text area is being typed into
		if(document.activeElement.id === "my_text")
		{
			//get the data in the field
			var text = $(this).val();

			//set number of characters
			var numofchars = text.length;

			if(numofchars <= max_length)
			{
				//set the length of the text into the counter span
				$("#counter").html("").html(text.length);
			}
			else
			{
				//make sure string gets trimmed to max character length
				$(this).val(text.substring(0, max_length));
			}
		}
	});
}

character_counter.js (Counts down without a character limit)

$(document).ready(function()
{
	//set max length
	var max_length = 10;

	//load in max characters when page loads
	$("#counter").html(max_length);

	//run listen key press
	whenkeydown(max_length);
});

whenkeydown = function(max_length)
{
	$("#my_text").unbind().keyup(function()
	{
		//check if the appropriate text area is being typed into
		if(document.activeElement.id === "my_text")
		{
			//get the data in the field
			var text = $(this).val();

			//set number of characters
			var numofchars = text.length;

			//set the chars left
			var chars_left = max_length - numofchars;

			//check if we are still within our maximum number of characters or not
			if(numofchars <= max_length)
			{
				//set the length of the text into the counter span
				$("#counter").html("").html(chars_left).css("color", "#000000");
			}
			else
			{
				//style numbers in red
				$("#counter").html("").html(chars_left).css("color", "#FF0000");
			}
		}
	});
}

Gist of both is that we need to set a max character count for the text area and then listen for the keyup event to fire. When this happens we then check if the text area with the id of ‘my_text’ is focused. If not there is no need to continue running code. If so we get the value of the text area and get the length which is the number of characters. If we are increasing our counter by one we just need to use jQuery to write to the span tag the current length of the value of the text area. If counting down we do the opposite. We subtract the length of the value of the text area from the max number of characters allowed. Next, if we are trimming the string so that it can never actually get longer than the number of allowed characters we check if the length has exceeded the max characters. If so we use the ’subString()’ method to make sure that the value is trimmed off each time the user tries to add a character. If running the counter into negative numbers we don’t really need to run any conditionals unless changing the color so that negative numbers show up different than positive numbers. In this case I just check if the length of the value exceeds the max length. If so I use the jQuery css() method to change the color of the text to red.

That’s really it. Not pretty, but functional and simple.

Using jQuery, AJAX, and Coldfusion to filter SQL results

Sunday, March 7th, 2010

The following post will explain the logic behind the ‘live’ search results that are becoming more and more popular on the web.  The idea is that you have a record set at hand ready to be searched as a user types into an input box what they are looking for.  While in traditional software programming this has never been a huge deal, the request/response nature of the web makes our lives as web developers a little more difficult.  To bypass the request/response model we let the searching happen via the client using AJAX.

For this example three files will be needed.  The client file (the file with the filter tool and search results), a javascript file to handle the AJAX and jQuery output, and a Coldfusion component to handle the data processing.  I’ve set up a demo here to check out so you’ll know what we’ll be building.

Let’s take a look at the client file first.

jquery_result_filter.cfm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!--- PROXY --->
<cfajaxproxy cfc="path.to.jquery_result_filter" jsclassname="filter">

<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Untitled Document</title>

		<!-- JQUERY LIBRARY -->
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>

		<!-- JQUERY_RESULT_FILTER.JS -->
		<script src="js/jquery_result_filter.js" type="text/javascript"></script>
	</head>

	<body>
		Filter:
		<input type="text" name="filter" id="filter" value="" /><br /><br /><br />

		<p>Data:</p>
		<div id="output"></div>
	</body>
</html>

We have here a a proxy at the top that allows us to make asynchronous AJAX calls to the Coldfusion server. For javascript we load in the jQuery library and our javascript file that handles the AJAX calls and the data output to the DOM. In the body there is an input field which serves as our filter and an empty div which will have data loaded into it dynamically using jQuery.

Let’s take a look at our component to see how the data is being processed as the user types their filter.

(more…)

Using WDDX instead of JSON to pass string of numbers

Tuesday, March 2nd, 2010

I’m a big fan of working with JSON data, but I did run into a snag that annoyed me a little the other day. Simply put JSON takes it upon itself to convert a string of numbers to a data type number. Normally I wouldn’t notice, but in this case I was trying to return a zip code that began with a zero. Each time it was returned, the zero had been eliminated. I returned it as just a string, ran it through the tostring() method and so forth. All with no luck.

In the end I packaged the zip code in a wddx packet.  This sets the value into some xml which types it as a string if it is a string despite the fact that it is all numbers.  When the data is returned it is returned as a string, keeping the leading zero.  I’ve set up a quick demo to illustrate this issue.  If you open it in the firebug console you will be able to see the JSON that is returned in comparison to the XML in the WDDX packet.

Also remember that if you are returning structs or arrays in JSON format you can store a WDDX packet as a JSON value-pair within the struct or array.  I’ve quickly showed this below.  If there is a way to control the data typing of JSON data I’d love to know how.

<!--- SET ZIP CODE --->
<cfset var zipcode = "02906">

<!--- CREATE A STRUCT --->
<cfset var data = structnew()>
<cfset data.success = true>
<cfset data.message = "This is some type of message.">
<cfset data.zipcode = "">

<!--- SET ZIP INTO A WDDX PACKET IN THE STRUCT --->
<cfwddx action="cfml2wddx" input="#zipcode#" output="data.zipcode">

Filtering on keypress without one character delay

Sunday, February 21st, 2010

If you’re using jQuery to filter SQL data in something like a grid or live search results you may find that the search filters according to the key pressed two times back.  For example if I’m searching for the word blue in an SQL table containing a bunch of colors it may work so that when I type ‘blu’ into the search tool it returns both ‘black’ and ‘blue’.  This is because it has not filtered according to the ‘u’ that was just typed.  This can lead to pretty confusing result listings for the user.  We’re not used to being on a one character delay.

If you’re having this problem luckily it’s a very minor thing.  If you’re jQuery is performing the filter on ‘keypress’ then this is your problem.  ‘keypress’ is pretty much the same as ‘keydown’.  As a result it performs the filter query before it knows what the key press is returning.  If you have a search field with an id of ’search’ your jQuery may look something like

$("#search").keypress(function()
{
     //do some type of filtering
});

So the search is being performed just before the new character is registered. To fix this just change ‘keypress’ to ‘keyup’. This will make sure that the search is not performed until after the new character has registered.  This way your filter will run with all of the characters in the search field.

The new jQuery would look something like the following:

$("#search").keyup(function()
{
     //do some type of filtering
});

Removing extra white space before returning JSON data

Monday, February 15th, 2010

Although generating HTML in a CFC is not always good practice, when you have the choice between generating the HTML in a CFC or with jQuery it might be best to go with the CFC.  The only reason I say this is for readability and updatability.  But remember that it’s always best to create the HTML structure on the front-end page and fill in the data with Coldfusion or on the spot with jQuery and AJAX.  So enough with the disclaimers.

Sometimes it is best to return a chunk of HTML to the browser built in a CFC.  For example an application I’m working on at the moment consists of a nutritional label for a line of food products.  I of course want the same label for each product, but with different data in each label.  On top of this the label is used in several places in the application.  To add one more layer of complexity, the application is very, very AJAX dependent.  So the label is not only used in multiple places, but updates via an AJAX proxy to a CFC when the product changes.  So in this case I opted to build my label with each call inside a <cfsavecontent> tag in a remote CFC.

When I began writing the application I was getting the data for the label via AJAX and returning it to some jQuery that used the html() method to write the html with the data returned from the CFC.  It worked just fine like this.  However, it didn’t take long for the client to want to make some very minor changes.  Maybe it’s just me, but my html label in jQuery was not very readable or easy to update.  At this point I moved the entire set of HTML to the CFC and just returned a save content variable to jQuery which output the label as a single prewritten chunk of code.

Once again this was just fine until I implemented the ability for the administrator to update the data in the label.  Double-clicking a piece of the data in the label opened that data in a text field where the data could be manipulated and saved.  The problem I found was that when the data became editable in the text area it was filled with a ton of white space around the data.  So much so that the actual data could not even be seen in the text area without deleting a slew of white space.  I went back and looked at the JSON that was returned and realized that all of my indentions and line breaks I created in the CFC for readability had carried over into the JSON.  Of course, the browser ignores this white space so the label was showing correctly, but text fields do not ignore it.

So how do we remove this spacing and breaks so that it doesn’t show up in input fields and certainly not when saved to the database? As usual someone else out there has built a UDF to handle removing extra formatting. The UDF can be found at cflib.org under ‘HtmlCompressFormat(sInput)‘.  It’s a fairly simple method, but from my use seems to work very well at removing extra formatting in HTML.

The method is written in script form, and since my CFC was working in tag form I quickly rewrote it to reflect a tag based structure.  They work exactly the same and the tag based version below is simply a copy of the original script form.  To use the UDF you just need to pass in the string to remove white space from.  The method defaults to level 2 compression which I’ve found perfectly fine.  But if you did want to more or less compression you can pass in a 1, 2, or 3 after the string.

Let’s look at an example.  We have a save content variable in a cfc in which we write some nice readable indented HTML.  Everything works fine when we output it in the browser.  But if we load that HTML into a text area or rich text area we notice a whole lot of white space around the content.  When we look at the JSON that is returned from the proxy call we notice a whole lot of ‘/t/t/t/t/t/t/t/n my content /t/t/t/t/t/t/t/t/n’ going on in the code.  These are the formattings we need to get rid of.  If this string is contained in a variable called ‘mystring’ we need to run this variable through the HtmlCompressFormat() method before inserting into a database or returning to the browser.  So our method call would look something like

<!--- RUN STRING THROUGH COMPRESS HTML METHOD --->
<cfset compressedstring = HtmlCompressFormat(mystring, 2)>

So when writing dynamic HTML to be returned dynamically by jQuery I keep this method handy. Lastly, I’ll post the tag based copy of the method below. And if you want to see the original at cflib.org click here.

<cfcomponent displayname="Compress HTML" hint="Compresses any HTML passed in." output="false">

	<!--- *****************************  COMPRESS HTML  ***************************** --->
	<cffunction name="compress" displayname="Compress HTML" description="Removes any extra whitespacing in HTML." access="public" output="false" returntype="String">

		<!--- PASS IN HTML AND LEVEL OF COMPRESSION --->
		<cfargument name="htmlString" displayName="HTML String" type="string" hint="String to be compressed." required="true" />
		<cfargument name="level" displayName="Compression Level" type="numeric" hint="Level of compression" default="2" required="false" />

		<cfset var stringToCompress = ARGUMENTS.htmlString>
		<cfset var compressionLevel = ARGUMENTS.level>

		<!--- TRIM OFF ANY EXTRA SPACES FROM STRING TO BE FILTERED --->
		<cfset stringToCompress = trim(stringToCompress)>

		<!--- RUN FILTER BASED ON SPECIFIED COMPRESSION LEVEL --->
		<cfswitch expression="#compressionLevel#">
			<cfcase value="3">
				<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", " ", "all")>
				<cfset stringToCompress = replace(stringToCompress, "> <", "><", "all")>
				<cfset stringToCompress = reReplace(stringToCompress, "<!--[^>]+>", "", "all")>
			</cfcase>

			<cfcase value="2">
				<cfset stringToCompress = reReplace(stringToCompress, "[[:space:]]{2,}", chr( 13 ), "all")>
			</cfcase>

			<cfdefaultcase>
				<cfset stringToCompress = reReplace(stringToCompress, "(" & chr( 10 ) & "|" & chr( 13 ) & ")+[[:space:]]{2,}", chr( 13 ), "all")>
			</cfdefaultcase>
		</cfswitch>

		<!--- RETURN COMPRESSED HTML --->
		<cfreturn stringToCompress>

	</cffunction>

</cfcomponent>

Use CSS: Why using jQuery to add a hover class is just wrong.

Tuesday, January 19th, 2010

I don’t know a ton about CSS, but I recently found myself needing to add a hover class to a fairly complicated ajax driven application.  I fought for several hours trying to use the jQuery .addclass() method on mouseover to add a hover class I created.  While this worked great on existing elements those created via ajax took no effect.  After scrambling through the code and calling my method a dozen times I finally had something that vaguely worked.  And just when I was ready to move on I thought I would torture myself by adding the CSS ‘:hover’ class to my original hover class and see what happened.  It worked perfect.  Freakin perfect.

I was convinced that ‘:hover’ could only be applied to <a> tags.  I was wrong.  It seems that it works in Firefox, Safari, and at least the later versions of IE.  So let’s let CSS do what it does so well, which is style, and jQuery do what it does so well, which is things other than styling.

New jQuery 1.4 delay() method

Saturday, January 16th, 2010

So the new jQuery 1.4 library was released a couple days ago.  I haven’t really had a chance to check out what all it has to offer.  Looks like a lot of speed enhancements.  Speed is always great, but this is a speed increase on top of jQuery 1.3, which I thought was pretty freakin fast to begin with.

Anyways, scanning the new stuff page on their site I noticed a new delay() method.  I actually just finished a small email list application that runs on jQuery and Coldfusion that I really wished at the time I had a nice easy to implement delay method.  And what do you know, a couple days later here I am with my precious delay.

So I wrote up a quick example of using this little gem.  I’ve just created a div that animates to the right, is delayed for the amount of time specified in a text input, and then animates back to the left.  Click here to see the example.  Otherwise, let’s look at some code.

The HTML

Number of Seconds to Delay:
<input type="text" name="seconds" value="" size="3" maxlength="3" />

<p id="animate">
	Animate
</p>

<div id="animatethis"></div>

Some CSS

<!--
	#animate {
		cursor: pointer;
		color: #3543ff;
	}

	#animatethis {
		width: 100px;
		height: 100px;
		position: absolute;
		top: 200px;
		left: 100px;
		background-color: #ff7780;
	}
-->

Quick summary before moving on. Our html creates an input box for the user to tell how many seconds they want the delay to be. Next is the word animate in a tag. This is what we will click to run the animation. The CSS gives this a pointer cursor to indicate it can be clicked and a blue color. Next is an empty div that we make 100 pixels by 100 pixels with a redish background and an absolute positioning at 200 pixels from the top and 100 pixels from the left.

So, moving on.

jQuery

$(document).ready(function()
{
	//listen for our animate click
	$("#animate").unbind().click(function()
	{
		//get the value of the seconds input
		var numofseconds = $("input[name='seconds']").val();

		if(numofseconds === "" || isNaN(numofseconds) === true)
		{
			alert("Please enter a valid number.");
		}
		else
		{
			//turn our seconds number into milliseconds
			var numofmilliseconds = numofseconds * 1000;

			//get the left position of our animated div
			var pos = $("#animatethis").position();
			var leftpos = pos.left;

			//animate the box
			$("#animatethis").animate({left: "+=100"}, 1000, function()
			{
				//show delayed message
				$(this).html("

delayed for " + numofseconds + " seconds!

");

				$(this).delay(numofmilliseconds).animate({left: "-=100"}, 1000, function()
				{
					$(this).html("");
				});
			});
		}
	});
});

When the animate button is clicked we get the value the user has specified for the number of seconds. If the user has not specified a number of seconds or specified something other than a number we throw an alert to let them know that they need to enter a valid number. If they did enter a valid number then we can proceed. The delay() method accepts its delay in milliseconds. So we need to convert the number the user entered into milliseconds. We can do this by simply multiplying the number of seconds by 1000. Next we need to get the left position of the div. Once we have this we can begin the animation. We animate it to the right 100 pixels. Once the animation is complete we run our callback function. Here we get to use our nifty delay to pause the animation back to the left. Since we’re already dealing with the div being animated we can use $(this).delay() where ‘this’ represents the box being animated. We pass in to the method the millisecond version of our seconds and proceed to animate back to the left. Much much simpler than using a timer in javascript.

Selecting input text with jQuery

Wednesday, January 13th, 2010

When you have a form, browsers usually highlight the text value of the selected input field when tabbing through. However, if the user clicks the field the text is not highlighted and the cursor is placed appropriately. This is certainly not a bad thing, and in most cases is what it should do. But if you do want the value of the input field to highlight when a user clicks into the field as opposing to tabbing into the field it can be done with jQuery. I typed up a quick example.

Create a Form

<form name="myform" method="post" action="##">
	<input type="text" name="input1" value="input one" />
	<input type="text" name="input2" value="input two" />
	<input type="text" name="input3" value="input three" />
	<input type="text" name="input4" value="input four" />
</form>

Now let’s look at the jQuery. Remember to first link to the jQuery library.

The jQuery

$(document).ready(function()
{
	$("form[name='myform'] input").unbind().click(function()
	{
		$(this).select();
	});
});

Fairly simple.  We just use jQuery to listen for a click on any input fields inside our form named ‘myform’.  When it is clicked we use jQuery’s select() method to highlight the text in the input field.

Returning HTML to jQuery with Coldfusion

Thursday, January 7th, 2010

I’ve spent the last couple months building an application that is very heavy on the front end with jQuery and reliant on Coldfusion and MySql for data processing and storage.While I’ve been using jQuery for some time now to pull off little cool things in more traditional server-request based applications, this project is really the first that I’ve worked on that has required me to really dig into what jQuery can really do.

Since I work with my wife, who also happens to be Art Director where we work, a position slightly higher than my own, I have to take very special care to make sure my code is easily editable on the CSS and HTML end.  I’ve found that, while manipulating HTML in the DOM with jQuery is incredibly simple, the format in which it has to be written is slightly unreadable and written in a portion of the javascript that the designer may not be able to easily locate when an edit needs to take place.

Let’s take a look at how jQuery would add a table to the DOM using the html() method.

$("#mydiv").html("<table class='mytable'><tr class='header'><td>Header 1 Content</td><td>Header 2 Content</td></tr><tr class='content'><td>Content 1</td><td>Content 2</td></tr></table>");

<div id="mydiv"></div>

(more…)

Changing the IE diaper!

Thursday, December 31st, 2009

I noticed a small bug with Internet Explorer 7 (and probably the rest of the versions) using the jQuery change() method.  Don’t ask me why, but it seems that IE remembers a change, but doesn’t register it until one click after the change actually occurred.  I’ve set up a little demo of what I’m talking about here.  Of course if you look at the demo in Firefox, Safari, Opera, or Chrome both examples will work perfectly fine.  But if you look at it in IE 7 you’ll see that the .click example works fine, but the .change example requires you to click an extra time to get the change to actually take place.

I don’t mean to be insensitive, but this is a change event.  I might understand this not working in IE 6.  This is IE 7. It was released in October 2006 according to Wikipedia.  That’s just a couple years ago.  This is a change event! This is the last day of 2009!  It probably doesn’t even work in IE 8!

Granted HTML standards do state: “The onchange event occurs when a control loses the input focus and its value has been modified since gaining focus. This attribute applies to the following elements: INPUT, SELECT, and TEXTAREA.” So first of all, according to the standards, we shouldn’t even be attaching the change event to a radio input, and second of all the change event actually occurs on blur.  So it seems that IE is maybe kind of following the rules here.  I just think it’s unfortunate that the only rule IE is following is the one rule that just doesn’t make a lot of sense to begin with.

Seriously, with just a touch of common sense Firefox, Safari, Opera, and Chrome uses the change method appropriately.

I wanted to get this post off before the end of the year so I can start the new out fresh, happy, and IE free (for a while).  And one last thing. If you happened to look at the demo and it opened in Internet Explorer by default, please – for the love of God download Firefox, Opera, or Chrome.  All are free and cross platform.  Even safari is not half bad on a PC.

HAPPY NEW YEAR!!!