Advanced button theming on jQuery UI Dialog

by drew on June 10, 2010

Check out the update to this post!

There is a very annoying bugfeature that I have found when using jQueryUI. It’s not the themes, they work great, in fact, they are the best thing since sliced bread. But in a ‘Cupertino.esc’ way, they provide too much simplicity over the functionality that I require. This post aims to solve that in a progressive enhancement sorta way. I am using jQuery 1.4.2. with jQuery UI 1.8.2, it doesn’t matter what theme you use with this, but I prefer redmond.

Let’s take a look at the core issue. Here is what a typical dialog looks like in jQueryUI 1.8.2 with some nice buttons.

Typical 'Redmond' jQueryUI Dialog

Perfect example of a jQueryUI Dialog

Here’s the simple code for this.

<article id="dialogs">
	<a href="javascript: void(null);" id="dialogbutton">Open Dialog</a>
	<div title="this is my test this is my test this is my test this is my test" id="dialogtest">
	This is a div dialog test. This is a div dialog test. This is a div dialog test. This is a div dialog test. This is a div dialog test.
	</div>
</article>
<script type="text/javascript">
	$(document).ready(function() {
		/* Create a dialog */
		$("#dialogtest").dialog({
                        title: "Alert!",
			modal: true,
			buttons: {
				"Ok": function() {
					$(this).dialog("close");
				},
				"Cancel": function() {
					$(this).dialog("close");
				}
			}
		});

		/* Add Dialog Button Functionality */
		$('#dialogbutton').click(function(){
			$('#dialogtest').dialog('open');
			return false;
		});
	});

</script>

That’s really great, I mean that code is so small and yet you can get such a great looking item out of it. So how can I have a problem with that? Well let me tell you how the buttons are made, you have a name and then you have that name point to a function. The name is the text of the button, the function is the action of the button. And that’s it. Period.

Now, I find it great that I can use these simplistic featuresets and get ‘get by’ but normally my “Cancel don’t ever touch me button” is the color red(ish) while my “Oh you need to hit me to move on” button is the color green(ish). But you cannot do that (easily) with this current setup. In fact it’s very sloppy to force this setup into doing that and it ends up using a great amount of code just to do one thing, add a class.

To solve this, I did what any self respecting JavaScript ninja would do, I said goodbye to jQuery UI I opened up the source code and took a peek, found out where I could attack (fix) the code and I did it.
So before I show you the code, I will show you how I decided buttons should/could be made. My process is 100% backward compatible, yet more difficult and easier to mess up (the original goal of jQueryUI was obviously to make it as simple as possible).

Buttons with my code changes can now be made like this

buttons: {
	"Ok":  function() {
		$(this).dialog("close");
	},
	"Cancel": {
		action : function() {
			$(this).dialog("close");
		},
		type : "cancel"
	}
/* This is poor CSS by design to be simple and readable */
 div.ui-dialog-buttonpane button.cancel { background:none; border:0px none;color:red; }

and the old way of doing it will still work just fine as well.

I’ve gone ahead and added a few features, namely it is now name-points-to-object instead of the old name-points-to-function mentality. This object has two attributes: action and type. Action is the old function() that was pointed to and it will be called when this button is clicked. Type is the new feature on the block, it’s just a CSS class that is added to the function using jQuery.addClass. I’ve tried to keep is simple, and at the same time, make it robust and backward compatible. Here’s a simple change that is possible using this feature.

A jQuery UI with different colored buttons

Now my dialogs can look like this when I want them to. This is a big usability thing (make the buttons descriptive, not just in text but in color/design and function).

So the secret sauce to all of this is actually an extension of the jQueryUI 1.8.2 Dialog code (more like rewrite of some of the code). This code can only be ran AFTER jQueryUI 1.8.2 has been created, otherwise you will get an error. I placed this code into the jQueryUI 1.8.2 custom.js file itself for easy keeping; just drop it at the bottom of the file.

/* TorchUI dialog button fix */
(function($) {
	var _createButtons = $.ui.dialog.prototype._createButtons;
	$.ui.dialog.prototype._createButtons = function(buttons) {
		var self = this,
		hasButtons = false,
		uiDialogButtonPane = $('<div></div>')
			.addClass(
				'ui-dialog-buttonpane ' +
				'ui-widget-content ' +
				'ui-helper-clearfix'
			);
		// if we already have a button pane, remove it
		self.uiDialog.find('.ui-dialog-buttonpane').remove();
		
		if (typeof buttons === 'object' && buttons !== null) {
			$.each(buttons, function() {
				return !(hasButtons = true);
			});
		}
		if (hasButtons) {
			$.each(buttons, function(name, fn) {
                        /* Begin the code change here */
			// Check to see if fn is being passed in as a funciton, assume it's an object if not.
			 	if(!$.isFunction(fn)) { 
			 		var buttonclass=fn.type;var func=fn.action; }
			 	else { 
			 		var func=fn; var buttonclass=""; }
				var button = $('<button type="button"></button>')
					.text(name) 
				/* Add a class to the button, if there is a class */
					.addClass(buttonclass)
					.click(function() { func.apply(self.element[0], arguments); })
					.appendTo(uiDialogButtonPane);
				if ($.fn.button) {
					button.button();
				}
			});
			uiDialogButtonPane.appendTo(self.uiDialog);
		}
	}
})(jQuery);

If you have questions, please respond, I promise not to take them personally :)

3 comments

This was great for a user-case where I wanted to add an ID, as well. It was easy enough to extend (I suppose I could have used a class. but, whatevs!).

HOWEVER

I had to back out of using it, as it conflicted with another, deeply-embedded-in-my-site plugin: JQueryUI MessageBox

I can’t readily see what the conflicts are (other than the MessageBox plugin using another trick to get custom buttons in a dialog).

by Michael Paulukonis on March 21, 2013 at 2:01 pm. #

Oh, !@#!@#.

I just saw your follow-up post that discusses new button-creation possibilities in the jQueryUI library.

Which I have not been able to find over the past week anywhere else.

BLARG!

by Michael Paulukonis on March 21, 2013 at 2:03 pm. #

Well, I hope that it works out for you. I’m not sure how valid some of this is for jQueryUI 1.9 but you can find out more directly from the source. On first glance, it still looks like my updated post is valid. http://api.jqueryui.com/dialog/#option-buttons

by drew on March 21, 2013 at 2:29 pm. #