Archive for the ‘JavaScript’ Category

I had a request to supply a sample HTML page that would send a subscriber’s email address to ColdFusion without reloading the page. So I figured I’d post it here for any others looking for a simple example. This method uses jQuery, AJAX and a ColdFusion component.

index.html or index.cfm

<!DOCTYPE html>
<html>
	<head>
	</head>
	<body>
		<div id="subscribeContainer">
			<input type="email"><button type="button">Subscribe</button>
		</div>
		<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>

		<script>
			(function($) {
				// bind the button with an event handler
				$('#subscribeContainer button').click( function(e) {
					// when button is pushed, POST data to remote ColdFusion component method
					$.post(
						'subscription.cfc',
						{
							method: 'subscribe',
							email: $('#subscribeContainer input').val()
						}
						)
						.done( function() {
							// everything worked
							$('#subscribeContainer').text('You have been subscribed.');
						})
						.fail( function() {
							// something failed
							$('
<span>There was an error subscribing.</span>').appendTo('#subscribeContainer');
						}
					);
				});
			})(jQuery);
		</script>
	</body>
</html>

subscription.cfc

component {

	remote void function subscribe( required string email ) {
		// call database insert method here
	}

}

I just created a JavaScript method that sorts a JavaScript object by key name case insensitive. Source at https://gist.github.com/CFJSGeek/5550678.

/**
 * Sort JavaScript Object
 * CF Webtools : Chris Tierney
 * obj = object to sort
 * order = 'asc' or 'desc'
 */
function sortObj( obj, order ) {
	"use strict";

	var key,
		tempArry = [],
		i,
		tempObj = {};

	for ( key in obj ) {
		tempArry.push(key);
	}

	tempArry.sort(
		function(a, b) {
			return a.toLowerCase().localeCompare( b.toLowerCase() );
		}
	);

	if( order === 'desc' ) {
		for ( i = tempArry.length - 1; i >= 0; i-- ) {
			tempObj[ tempArry[i] ] = obj[ tempArry[i] ];
		}
	} else {
		for ( i = 0; i < tempArry.length; i++ ) {
			tempObj[ tempArry[i] ] = obj[ tempArry[i] ];
		}
	}

	return tempObj;
}

I recently developed my first jQuery UI Custom Widget using the jQuery UI Widget Factory. I found the Widget Factory to be a nice framework for what I needed to do and took away a bit of the complexity normally needed for a UI plugin.

It did introduce a level of complexity for live event binding. For example, I want all dynamically generated anchor tags to run a method when clicked.

The Widget Factory wants us to use the “this._on” method to accomplish this. The Widget Factory is a little undocumented so it was hard to figure this one out.

At first I tried the following:

$.widget( "CFWT.myWidget", {

	_create: function() {
		this._on('.myClass', {
			click: function(event) {
				var $container = $(event.target);
				doSomething($container);
			}
		});
	}
	
	_doSomething: function(container) {
		console.log(container);
	}

});

However I quickly found out that the event was only bound with any classes created the first time. After some Q&A on Stack Overflow I finally figured out the correct way.

$.widget( "CFWT.myWidget", {

	_create: function() {
		this._on(this.element, {
			'click.myClass': function(event) {
				var $container = $(event.target);
				this._doSomething($container);
			}
		});
	}
	
	_doSomething: function($container) {
		console.log($container);
	}

});

This new code will bind any “myClass” class that is created inside the widget’s container. If you want it document wide then replace “this.element” with “document” or another container.

You may also notice that I use “$(event.target)” instead of “this”. That is because “this” doesn’t change to the event. Instead, I believe, it remains at the widget level, which can be pretty confusing.

A working example can be found at http://jsfiddle.net/vEAhq/8/

Sublime Tern

Posted: May 8, 2013 in JavaScript, Sublime Text
Tags: ,

Thanks to Emmet for releasing the “Sublime Tern” package. It implements TernJS into Sublime Text.

“TernJS is a JavaScript type inference engine written by Marijn Haverbeke. It analyses your JS code on-the-fly and provides autocompletion, function argument hints, jump-to-definition, and various automatic refactoring operations.”

I like stuff that “just works”, but since this package is pretty new it lacks a bit of documentation and Q&A.

I did also try the newly released official “TernJS for Sublime” package but that just became complicated compared to Emmet’s version and seemed to slow the editor way the heck down. So I uninstalled that rather quickly. I’m sure it’ll become much better as time goes on.

If you take a look at the TernJS Demo, you’ll see right away that using Ctrl-Space after the characters “co” will auto-complete to “console” or “confirm”. This is something I expected to “just happen” in the Sublime Tern package. But to my horror, it appeared that it just didn’t work.

After some discussion in GitHub, I finally figured out that you have to add some libraries into the project settings, which is kind of annoying. But I did just see that they released a new update to GitHub just now that will accept defaults for library loading which will be quite nice.

But basically here’s the answer to solve what appeared to be “broken” to me. Add this config object to your sublime-project file (Project > Edit Project):

"ternjs": { "libs": ["browser"] }

But I almost always use jQuery so I also added that:

"ternjs": { "libs": ["browser", "jquery"] }

Now I see the auto-completion options I was looking for.

If you program in JavaScript I highly recommend installed one of the two TernJS packages.

The reason I looked so deeply into this was because Adobe’s Brackets implemented it and it was touted as a great feature to have!

On a current project, the website was and many interactive jQuery “modules” where supplied by a 3rd party designer. We I pieced it together with ColdFusion everything worked great on IE8+, FF and Chrome. However it was soon discovered that a large customer of the client couldn’t upgrade past IE7 at the moment. After running the JavaScript through jsLint, that fixed the majority of the issues. Heck, just a couple of commas out of place will make a nightmare out of IE7.

However there was an issue that took me a whole day to figure out. (We’re talking thousands of lines of code to debug with no error being thrown).

As a general description, the site is a customized e-commerce site in its basic functionality. It has a category navigation tree to the left, with a product result grid to the right. When an item on the grid is clicked, the grid is hidden and replaced by a product detail section populated via AJAX.

First of all, there where around 1,500 categories that where populated into the DOM on page load via an un-ordered list. It was then converted into a cascading tree. The way you’re supposed to do it for accessibility and SEO purposes right? Well, IE7 didn’t take too kindly to that and took about a whole minute to display. IE8+ took probably around a second.

To resolve this issue I created a jQuery UI Widget via the Widget Factory. This required upgrading the version of jQuery being used, and I chose the latest one at 1.9.1 that still supported IE7.

After the tree was created and implemented, it became clear that only one product in the product grid was showing as opposed to the 15 for each page.

I determined that jQuery 1.7.2 loaded the grid as expected, but both 1.8 and 1.9 versions only loaded one. The method used to populate the grid was to clone a hidden div, populate it, append it to the parent container and make it visible using data from an AJAX JSON data set. It was looped via an $.each() method.

Because there where no errors being thrown, and I needed that newer version of jQuery I started the process of elimination. That process took me to the bitter end. I found that I couldn’t use multiple elements inside a selector. For example:

$('#myDIV1,#myDIV2').hide();

The above would inhibit all but one cloned container to be displayed. The workaround was to split up the selectors:

$('#myDIV2').hide();
$('#myDIV2').hide();

This would only happen in IE7. IE8+, FF, and Chrome worked just fine. It also only happened in jQuery 1.8+.

I could reproduce this any time, ripping out most of the app down to the essentials.

However at this time, creating a basic app in another virtual site works just fine. I may try to figure it out at a later time, but right now I can’t duplicate the issue.

But I’m writing this in case anyone runs into this edge case and needs a workaround. Hopefully I can find the cause and submit a bug to the jQuery team.

img Element error Event

Posted: January 8, 2013 in JavaScript
Tags: , , , , , ,

If you develop and push to production, you most likely have experienced broken images on your dev instance. You may have also run into broken images on production due to user/admin error, etc. Wouldn’t it be nice if you could display a default placeholder image without having to take a hit on your file system, checking to see if it exists, before your load each image?

Thanks to Ryan Stille’s recent blog post, I have been made aware of a (not so great) solution. Apparently the img tag, along with others such as object, script and style have error events. We can listen for the error event and load a placeholder image in place of the default browser error image.

The catch is the event handler must be attached before the browser fires the error event. Also, the error event may not be correctly fired when the page is served locally. The error event relies on HTTP status codes and will generally not be triggered if the URL uses the “file:” protocol.

In┬ásimpler┬áterms, the only solution I’ve found is to either place the event handler inline with the img tag, assign the img src via JavaScript or recursively search each image’s complete state or naturalWidth once the window is done loading. I’ve tried using “$().on()” and “$(“img”).error()” both after the document loads and inline before the element is loaded. However neither solution works, which doesn’t make much sense to me.

I am including multiple examples because this is not a one-solution-fits-all scenario.

The first working example displays a placeholder image using the inline method if the error event is thrown. Notice the onerror handler is reset when it’s run so you don’t run into an infinite loop if your placeholder image also fails.

<img src="images/myImage.jpg" alt="My Image" onerror="imageError(this)">

<script>
function imageError(element) {
    element.onerror='';
    element.src='/images/imgPlaceholder.png';
}
</script>

The second working example, also using the inline method, will call a script that will report the broken image and load the placeholder. The script returns an image with the proper image MIME type.

<img src="images/myImage.jpg" alt="My Image" onerror="imageError(this)">

<script>
function imageError(element) {
    element.onerror='';
    element.src='logBrokenImage.cfm?image=' + element.src';
}
</script>

The third working example uses JavaScript to load the image and displays a placeholder if that image fails to load.

<img id="myImage">

<script>
    $('img').one( 'error', function() {
        $(this).attr( 'src', '/images/imgPlaceholder.png' );
    });

    $('#myImage').attr( 'src', 'myImage.jpg' );
</script>

The final working example recursively searches through each image after the window loads. If it finds the state incomplete or the natural width of the image is 0, then it loads the placeholder image.

<img src="images/myImage.jpg" alt="My Image">

<script>
$(window).load(function() {
    $('img').each(function() {
        if ( !this.complete || ( !$.browser.msie && ( typeof this.naturalWidth == "undefined" || this.naturalWidth == 0 ) ) ) {
            this.src = '/images/imgPlaceholder.png';
        }
    });
});
</script>

I’m working with some code that’s been worked over many, many times over the years. It could a thorough scrubbing, but that’s not in the scope of my request.

I just upgraded the jQuery UI to version 1.9.2 and jQuery to 1.8.3 and added a simple dialog.

test_dialogIt was expected that the dialog would center itself to the browser window. However it appeared to be centering itself to the html element and scrolling the page to make it centered if the content was longer than the window height.

Here’s the code:

<html>
<head>
    <title>My Title</title>
</head>
<body>
    <div id="userNoticeDialog" style="display: none;" title="Notice">
        test content
    </div>

    <script type="text/javascript">
        $("#userNoticeDialog").dialog();
    </script>
</body>
</html>

After a process of elimination and seeing that there was no doctype declared, I tried adding a doctype. That resolved the issue.

<!DOCTYPE html>
<html>
<head>
    <title>My Title</title>
</head>
<body>
    <div id="userNoticeDialog" style="display: none;" title="Notice">
        test content
    </div>

    <script type="text/javascript">
        $("#userNoticeDialog").dialog();
    </script>
</body>
</html>

I believe the reason was the lack of a DOCTYPE caused the (Chrome) browser to go into quirks mode, while the inclusion of the DOCTYPE caused the (Chrome) browser to go into standards mode. However, I’m not sure how to detect which mode the Chrome browser is currently in. Does anyone know?