Posts Tagged 'jquery'

the jTemplates experiment

So it took a heck of a long time between the first proofs of concept and actually going live, but I rewrote a pretty complex client-based web application to use jTemplates. It started out with 12k+ lines of code (the numbers in that previous post don’t reflect various utility files, just the two main ones) and when I totaled it up on Monday, the new count is 3834. I’d been estimating it at about 5k. Less than 4k is better than I’d hoped. Even more impressive is that the previous figure did not include all the HTML templates that provided the pages their basic structure – the 3834 includes the jTemplates (since they’re all Javascript), meaning that’s it.

Summary: I am now a fanatical jTemplates convert.

However, I had a conversation over the weekend that’s got me questioning whether I’m sacrificing too much performance for maintainability. I won’t pretend the new application runs a lot faster than the old one. Its issues are different – this takes a long time to load, whereas the old one leaked memory over time – but it’s not blazing fast by any means. Part of the problem is the immense data object that the jTemplates process. All the information about a specific object is passed down at once when the page first loads, and then has to be pulled down again whenever the user switches between the four tabs in the application because of some irritating issues with the web services (the only thing they return is error messages, so if a new element is added, for example, it takes an additional XHR to find its ID) and data getting stale. I’m wondering, if I’m pulling down all this data anyway, if there’s an argument for putting jTemplates on the server and just getting the markup pre-loaded with the data points.

Of course, this is a .NET environment where I have pretty much no control over the backend, so it’s not likely I’ll get to try jTemplates on the server. I can’t find evidence that anyone’s ever tried that, so who knows, maybe it’s impossible.. Instead I’m going through all my notes from txjs and applying every performance enhancement I can find to any code I’ve touched over the past couple days. It’s not giving me an improvement so far, and I’m beginning to feel this is a design problem. If there were a way to split up the data being pulled down and lazy load interface elements, I think things would speed up a lot. Sadly, there’s (currently) not.

I’m left with 4k lines of Javascript I’m very pleased with having shrunk and no clear path forward, which fucking sucks. But the application is clearer and more well organized. I guess the experiment continues..

hierarchies, taxonomies, categories, drill-downs, etc.

I searched all over the place for a tidy pattern to deal with displaying hierarchical data for selection (as in a set of categories and sub-categories or a taxonomy), and couldn’t find anything. I think everyone’s aware of how this can be done with AJAX, but I wanted something that would still work without needing Javascript or a round-trip to the server each time a parent category changed. Obviously that means storing the entire taxonomy on the page, which is only realistic for some uses of this sort of control, but it’s those uses I’m interested in.

My solution is to load the entire taxonomy into an unordered list and include a radio button in each list item. This shows the hierarchy clearly and lets the user select a node of any depth (a requirement in my case). I use some Javascript to hide the radio buttons and show/hide child lists based on clicks on the list items themselves, then check the radio buttons behind the scenes. I’m wondering if this is the best possible solution for my circumstances. My hope is that neatly organizing the data in this way makes it more accessible, but I’m no accessibility expert.

The HTML itself is pretty simple (excuse the junk data):

<div id="taxonomy">
	<ul>
		<li><input type="radio" name="ghj" value="A" /> A
			<ul>
				<li><input type="radio" name="ghj" value="I" /> I
					<ul>
						<li><input type="radio" name="ghj" value="1" /> 1
							<ul>
								<li><input type="radio" name="ghj" value="a" /> a</li>
								<li><input type="radio" name="ghj" value="b" /> b</li>
								<li><input type="radio" name="ghj" value="c" /> c</li>
								<li><input type="radio" name="ghj" value="d" /> d</li>
								<li><input type="radio" name="ghj" value="e" /> e</li>
							</ul>
						</li>
						<li><input type="radio" name="ghj" value="2" /> 2</li>
						<li><input type="radio" name="ghj" value="3" /> 3</li>
						<li><input type="radio" name="ghj" value="4" /> 4</li>
						<li><input type="radio" name="ghj" value="5" /> 5</li>
					</ul>
				</li>
				<li><input type="radio" name="ghj" value="II" /> II</li>
				<li><input type="radio" name="ghj" value="III" /> III
					<ul>
						<li><input type="radio" name="ghj" value="6" /> 6
							<ul>
								<li><input type="radio" name="ghj" value="f" /> f</li>
								<li><input type="radio" name="ghj" value="g" /> g</li>
								<li><input type="radio" name="ghj" value="h" /> h</li>
								<li><input type="radio" name="ghj" value="i" /> i</li>
								<li><input type="radio" name="ghj" value="j" /> j</li>
							</ul>
						</li>
						<li><input type="radio" name="ghj" value="7" /> 7</li>
						<li><input type="radio" name="ghj" value="8" /> 8</li>
						<li><input type="radio" name="ghj" value="9" /> 9</li>
						<li><input type="radio" name="ghj" value="10" /> 10</li>
					</ul></li>
				<li><input type="radio" name="ghj" value="IV" /> IV</li>
				<li><input type="radio" name="ghj" value="V" /> V</li>
			</ul>
		</li>
		<li><input type="radio" name="ghj" value="B" /> B</li>
		<li><input type="radio" name="ghj" value="C" /> C</li>
		<li><input type="radio" name="ghj" value="D" /> D</li>
		<li><input type="radio" name="ghj" value="E" /> E</li>
	</ul>
</div>
The finished product with some simple styling

The finished product with some simple styling

Styling is split up so that positioning the child lists doesn’t interfere with the display of the un-enhanced version:

	#taxonomy { padding: 50px; background-color: #fff; height: 300px; }
	#taxonomy ul {
		margin: 0px 0px 0px 10px;
		padding: 10px;
		border: 1px solid #ccc;
		-moz-border-radius: 10px;
		-webkit-border-radius: 10px;
		border-radius: 10px;
		list-style-type: none;
		background-color: #fff;
	}
	#taxonomy ul.dyn {		
		position: absolute;
		left: 50px;
		top: 50px;
		height: 280px;
		width: 180px;
	}
	#taxonomy ul ul { border-color: #fff; }
	#taxonomy ul.dyn ul
	{
		position: absolute;
		top: 0px;
		left: 200px;
		display: none;
		height: 280px;
		width: 180px;
	}
	#taxonomy ul.dyn li:hover {
		border: none;
		background-color: #eee;
		-moz-border-radius: 10px;
		-webkit-border-radius: 10px;
		border-radius: 10px;
		width: 100%;
		padding-right: 30px;
		z-index: -1;
	}
	#taxonomy ul.dyn li > ul { background-color: #eee; border-color: #eee; }
	#taxonomy ul.dyn ul li:hover, #taxonomy ul.dyn ul li > ul { border-color: #ddd; background-color: #ddd; }
	#taxonomy ul.dyn ul ul li:hover, #taxonomy ul.dyn ul ul li > ul { border-color: #ccc; background-color: #ccc; }
	#taxonomy ul.dyn ul ul ul li:hover { width: auto; padding-right: 0px; }

Finally, some Javascript breaks the list up and provides its positioning:

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
	<script type="text/javascript">
	$(document).ready(function () {
		$("#taxonomy > ul").addClass("dyn");
		$("#taxonomy input").css("visibility","hidden");
		$("#taxonomy li").each(function (i) {
			$(this).bind("click",function(e) {
				$(this).siblings().find("ul").hide();
				$(this).children().find("ul").hide();
				$(this).children("ul:first").show();
				var rad = $(this).children("input");
				rad.attr("checked","true");
				return false;
			});
		});
	});
	</script>

Initially, I was using a noscript block to add this style: input:checked ~ ul {display:block;} and the only visual change the Javascript made was to hide the radio buttons (there was no “dyn” class). That works very well in modern browsers if your hierarchy is only two levels deep or users can only select from the lowest level, as in the classic example of vehicle make, model, and year. It didn’t work for my purposes, though, because users can select from any of four levels. It’s an easy change to make, though. The only thing to check is that IE6 is getting the correct styling, since it won’t recognize many of the selectors used here. I’m going to create a special script to handle that, but if you weren’t encumbered by that browser you could skip that step entirely.

Whew! So.. Is there a better way to accomplish this?


RSS Recent posts on the live version of this blog

  • An error has occurred; the feed is probably down. Try again later.