Using jQuery’s trigger for automated interfaces

Update: There is now a simpler and complementary example of the principles detailed here in the form of JQuery trigger and JS Function Call revisited.

The problem at hand that jQuery’s trigger functionality will solve is automation while at the same time facilitating implicit code reuse. We already have an interface that responds to button clicks, each button click will import statistics from a third party, display the stats and an import button, which when pressed will import the displayed stats.


Both fetching and import happens through Ajax calls, this is a functionality that we want to keep. What we want to add is the ability of simply pressing one button to be able to fetch stats from all partners and then press another button to import it.

Import in a responsible manner mind you. If we simply dispatched all the Ajax calls at once the server would probably be taxed too much, especially during import. Fetching doesn’t touch the database so could probably be done all at once but we play it safe here.

So the goal here is to use the current interface in order to first import all data through one click and then import it through another, a grand total of 2, as opposed to the current situation where at least 30 clicks are required. The most important thing though is that the user can simply walk away during fetch, come back, check the numbers and if they are OK press another button to import and do something else during import. A massive time saver.

So the plan is to start fetching the first partner and when the Ajax call returns we trigger the next fetch, the same goes for the import.

Let’s go through the logic as it was before we implemented automation:

var basePath = "/some/url/";

$("div[id^='display-']").find("button").click(function(){
	var me 		= $(this).parent(); 
	me.html( '<img src="/phive/images/ajax-loader.gif"/>' );
	var myId 	= me.attr("id").split("-").pop();
	var date 	= new Date();
	$.post(basePath + "upload_ajax.php", {partner_id: myId, time: date.getTime()}, function(res){
		me.html( '<button>Confirm</button>' + res );
		btn = me.find("button");
		
		var results = me.find(".parse_results");
		var form 	= results.find("form");
		$.scrollTo(btn.position().top - 50, {speed: 500});
		
		var stats 	= form.find("input[name='stats']").val();
		var date 	= form.find("input[name='date']").val();
		form.find("input[name='confirm']").remove();
		
		btn.click( function(){
			me.html( '<img src="/phive/images/ajax-loader.gif"/>' );
			$.scrollTo(me.position().top - 50, {speed: 500});
			$.post(basePath + "upload_ajax.php", {partner_id: myId, date: date, stats: stats, confirm: "yes"}, function(res){
				me.html( res );
			});
		});
	});
});

1.) We begin by looping through all divs whose id starts with display-. After the hyphen we have the partner id, for example: display-25. What we’re after is their button element which will get a new click binding.

2.) We display an animated gif that indicates we are now loading stuff, get the partner id and dispatch it and a timestamp to the server.

3.) We get the data back from the server and display the results plus a new Confirm button in the parent of the currently clicked Import button, what that means is that through the html() call the import button and the loader gif will be replaced with new content (they were the old innerHTML).

4.) The next few lines have to do with me simply outputting the legacy HTML that was used in the prior version of the interface before I started to ajaxify it. That’s why we need to make some modifications, getting rid of an old confirm submit button for instance. But most importantly we need to fetch the statistics which is a serialized PHP array in the value field of the hidden input with the name stats. We use the scroll to library to scroll to the top of the currently imported stats, this helps immensely since the most important stuff is at the top in our case, helps us save a lot of scrolling time for the user.

5.) When the confirm button is clicked we display the loader again and dispatch the fetched stats to the server, it will return something like “Stats imported successfully” which we display in the innerHTML.

So that was the non-automated version, let’s take a look at what we need in order to automate this by first revisiting parts of the above code listing:

btn.click( function(){
		me.html( '<img src="/phive/images/ajax-loader.gif"/>' );
		$.scrollTo(me.position().top - 50, {speed: 500});
		$.post(basePath + "upload_ajax.php", {partner_id: myId, date: date, stats: stats, confirm: "yes"}, function(res){
			me.html( res );
			if(automtic_import == true)
				$("#display-"+partner_ids.pop()).find("button").trigger('click');
		});
	});
	
	if(automatic == true)
		$("#display-"+partner_ids.pop()).find("button").trigger('click');

As you can see we have two new global flags, automatic and automatic_import. If automatic is set to true it means we are fetching stats in an automated fashion, if automatic_import is set to true it means we are doing ditto with regards to the import.

The if check to see if automatic is set to true happens when the first import button is clicked and after we receive the fetched results, if it is set to true we use a global variable called partner_ids which contains all the ids of the partners we are currently working with.

As you can see we pop it to get the next id in line while at the same time shortening it. Pretend it looked like this: [1 2 3]. We would then start with partner 3 and when the stats from partner 3 displays we immediately pop off 2 and use it to trigger a button click on the button whose parent div id is display-2. And so on until the partner_ids global is empty.

Exactly the same system is used when we import but then we use the automtic_import global instead. This system using find(“button”) works as long we make sure there is only one button element displayed in each “display-” div at a time.

So from reading the above we can conclude that we must now have two extra buttons, one that starts the automated fetching and one that starts the automated importing. Their setup looks like this:

$("#start_auto_btn").click(function(){
		automatic = true;
		runAutoMode();
	});
	
	$("#start_auto_import_btn").click(function(){
		automtic_import = true;
		runAutoMode();
	});

Not much to add here, let’s move to the final listing where runAutoMode will be explained.

var partner_ids = [];
var automatic = false;
var automtic_import = false;

function buildIds(){
	$("div[id^='display-']").each(function(){
		partner_ids.push( $(this).attr("id").split("-").pop() );
	});
}

function runAutoMode(){
	buildIds();
	$("#display-"+partner_ids.pop()).find("button").trigger('click');
}

BuildIds will create the array of all partner ids by looping through the display- divs, runAutoMode will simply start the automation by triggering the first trigger.

Related Posts

Tags: , ,