Multiple select lists with jQuery and JSON


This tutorial will all be about managing loading data into multiple select lists and then save the selections in the list.

There will be two multiple selects, one with a list of sites that will display a selection of partners, when a site is selected in the single select list the partners that have previously been mapped to it will automatically be selected in the multi select box listing them.

Let’s start with JS code working on a select box with the id partner_sites:

$(document).ready(function(){
	$("#partner_sites select option").click(function(){
		var siteId = $(this).val();
		$.post(window.location.href, {func: "jsonSitePartners", site_id: siteId}, function(res){
			var partners = $.evalJSON(res);
			if(partners.length > 0){
				$("#partners_list").find("option").attr("selected", false);
				$.each(partners, function(){
					$("#partners_list").find("option[value='"+this.partner_id+"']").attr("selected", true);
				});
			}else
				$("#partners_list").find("option").attr("selected", false);
		});
	});
});

When we click a site the following happens:
1.) We get the site’s id, it is in the clicked option’s value.

2.) We call a PHP method (which will be described shortly) called jsonSitePartners by way of AJAX, and we pass it the selected site’s id.

3.) We will now get a list of partners in the form of a JSON string which we will evaluate with the help of JQuery JSON.

4.) We now have our partners as JavaScript objects in an array which we can loop through with the jQuery utility function each.

5.) During each loop we try and find an option containing each partner’s id in its value attribute, if we find one we select it, if not we unselect it, the reason for doing that is that any partner might have been selected already since we might have clicked another site before the currently clicked site. An alternative could have been to first unselect all partner options before we started looping with each.

function jsonSitePartners(){
	$partners = array();
	foreach($this->getSitePartners($_POST['site_id']) as $partner)
		$partners[] = array('full_name' => $partner->full_name, 'partner_id' => $partner->partner_id);
	echo json_encode($partners);
}

Not much to add here, getSitePartners will query a linktable linking partners and sites for all partners belonging to the current site. After that we do some filtering which really should have been done in the MySQL query but that’s life sometimes when you work with other people’s code, you’re bound to get technical debt because you are either 1) too scared to change things for fear of breaking something else or 2) too lazy.

function savePartners(){
	var partner_ids	= [];
	var siteId = $("#partner_sites select option:selected").val();
	$("#partners_list option").each(function(){
		if($(this).attr('selected'))
			partner_ids.push( $(this).val() );
	});

	$.post(window.location.href, {func: "saveSitePartners", site_id: siteId, ids: $.toJSON(partner_ids)});
	$("#msgs").html("Partners saved.");
}

So after we have successfully selected all the current partners of our site and then some more, or removed some maybe, we need to be able to save them. To do that we need two things, the ids of the partners we want to map to the currently selected site and of course the id of the currently selected site.

The id of the site can be had by checking which of the options in the site single select list has been selected. Next we loop through the partners and store all the ids of selected partners in an array.

Finally we JSON encode and AJAX post everything to a PHP method called saveSitePartners:

function saveSitePartners(){
	$ids = json_decode($_POST['ids']);
	$this->sql->query("DELETE FROM partners_site WHERE partner_id IN(".implode(',', $ids).")");
	foreach($ids as $pid)
		$this->sql->insertArray('partners_site', array('partner_id' => $pid, 'site_id' => $_POST['site_id']));
	echo "ok";
}

First we decode the JSON and then we can use the fact that we now have an array by using implode on it with the help of a comma as glue, the result is something that can be used in the IN() SQL method, an often used “trick” of mine.

First we delete all partners belonging to the currently selected site from the link table, then we proceed by inserting them one by one, yet again not very clever since we’re doing repeat queries but this will not be a common operation so we can afford to be somewhat slow here.

Related Posts

Tags: , , , , ,