Adding AJAX to Joomla 1.5 with jQuery


This piece will build on the prior piece, this time we’ll take a look at how we can implement quick and dirty AJAX, using the very same class we went through in the prior tutorial.

We’ll also take a look at a case scenario where we use our stuff to add functionality to Joomla’s admin interface.

We begin with creating a new file in the root folder and naming it ajax.php, it looks like this:

$GLOBALS['ajax'] = true;
define( '_JEXEC', 1 );
define('JPATH_BASE', dirname(__FILE__) );
define( 'DS', DIRECTORY_SEPARATOR );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
JDEBUG ? $_PROFILER->mark( 'afterLoad' ) : null;
$mainframe =& JFactory::getApplication('site');
$mainframe->initialise();
JPluginHelper::importPlugin('system');
JDEBUG ? $_PROFILER->mark('afterInitialise') : null;
$mainframe->triggerEvent('onAfterInitialise');
require_once('plugins/community/community_ext.php');
cExt( $_POST['func'] );

As you can see it’s just the normal index.php file chopped in half where we keep the first half. At the end we include the community_ext.php file just like we do in the index.php file.

Finally we call the cExt function, this time with an argument in the post array, that must mean the function looks different now:

function cExt($func = ''){
	$cext = null;
	if(!empty($GLOBALS['cExt']))
		$cext = $GLOBALS['cExt'];
	else{
		$GLOBALS['cExt'] = new plgCommunityExt();
		$cext = $GLOBALS['cExt'];
	}
	if(empty($func))
		return $cext;
	else{
		if($GLOBALS['ajax'] == true)
			$cext->$func();
		else
			return $cext->$func();
	}
}

So if we pass a string as argument and the ajax key in the globals array is set we will simply call a function with the name in the string. We won’t return because we echo our results in AJAX calls.

When it comes to usage, let’s start with the HTML which I unfortunately have hard hacked into the admin interface of the igallery component, the goal is to be able to tag users to individual pictures in galleries. Just like on FaceBook.

. . .
<script type="text/javascript" src="<?php echo cExt()->baseUrl.'jquery.js'?>"></script
<script type="text/javascript" src="<?php echo cExt()->baseUrl.'paceville.js'?>"></script>
. . .
<div id="tags_<?php echo $row->id ?>">
	<?php foreach(json_decode($row->tagged) as $usr): ?>
		<div id="remove_<?php echo $row->id ?>">
			<?php echo $usr[1] ?> <img src="images/publish_x.png" style="cursor:pointer;" onclick="javascript:removeTag(<?php echo $row->id.','.$usr[0] ?>)">
		</div>
	<?php endforeach ?>
</div>
<div style="cursor:pointer;" onclick="javascript:showTagForm(<?php echo $row->id ?>)">Add</div>
<div id="tagform_<?php echo $row->id ?>" style="display:none;">
	<input type="text" id="user_search_<?php echo $row->id ?>" />
	<div id="result_<?php echo $row->id ?>">
	</div>
</div>
. . .

I’m contemplating using an intermediary connection table instead of JSON strings in an extra column called tagged. As you can infer the current solution won’t allow us to see all the pictures a user is tagged in, but we can very easily and quickly see all the users who are tagged to a certain picture and that is what the current specification is all about. However I have the feeling that this might change though…

Anyway, so we have the ability to remove stuff through removeTag() and add stuff through showTagForm() which will show the form used to connect users to pictures, note that it starts hidden (display:none).

Let’s begin with the adding functionality in paceville.js:

jQuery.noConflict();

function removeTag(img_id, usr_id){
	jQuery.post("/ajax.php", {func: 'updateTaggedUsers', imgid: img_id, usrid: usr_id, remove: "yes"});
	jQuery("#remove_"+img_id).remove();
}

function updateTags(usr_id, img_id, usr_name){
	jQuery.post("/ajax.php", {func: 'updateTaggedUsers', imgid: img_id, usrid: usr_id});
	jQuery("#tags_"+img_id).append('<div id="remove_'+img_id+'">'+usr_name+' <img src="images/publish_x.png" style="cursor:pointer;" onclick="javascript:removeTag('+img_id+', '+usr_id+')"/></div>');
}

function showTagForm(img_id){
	var frm = jQuery("#tagform_"+img_id);
	frm.show("slow");
	var inpt = jQuery("#user_search_"+img_id);
	inpt.keydown(function(event){
		if(inpt.val().length > 3){
			jQuery.post("/ajax.php", {func: 'getUserListByPartial', name: inpt.val()}, function(res){
				res = eval( '(' + res + ')' );
				str = '';
				jQuery.each(res, function(){
					str += '<div style="cursor:pointer;" onclick="javascript:updateTags(' + this.id + ', ' + img_id + ', \'' + this.name + '\')" >' + this.name + '</div>';
				});
				jQuery("#result_"+img_id).html(str);
			});
		}
	});
}

Let’s discuss the noConflict() call first. Since Joomla is using MooTools everywhere we need it, jQuery will simply have to defer to MooTools here in light of its heavy usage pretty much everywhere. That’s also why we use jQuery instead of $.

Note how we show a list of users by displaying the result of the function getUserListByPartial, however we don’t start issuing AJAX calls unless we have more letters than three in the box to avoid too many results.

Once the names start to appear they can be clicked in which case we use updateTags() which in turn calls the updateTaggedUsers PHP method and adds the newly tagged user to the list of users already in the picture, straightforward enough, let’s look at the PHP:

function getUserListByPartial(){
	$sql = "SELECT DISTINCT username, name, id FROM `jos_users` WHERE `name` LIKE '%{$this->postArr['name']}%'
			OR `username` LIKE '%{$this->postArr['name']}%'";
	echo json_encode($this->loadObjectList($sql));
}

function updateTaggedUsers(){
	$img_sql = "SELECT * FROM `jos_igallery_img` WHERE `id` = {$this->postArr['imgid']}";
	$usr_sql = "SELECT * FROM `jos_users` WHERE `id` = {$this->postArr['usrid']}";
	$usr = $this->loadObject($usr_sql);
	if(empty($usr)){
		echo "no user";
		return;
	}
		
	$img = $this->loadObject($img_sql);
	if(empty($img->tagged))
		$img->tagged = json_encode(array(array($usr->id, $usr->name)));
	else{
		$tmp = json_decode($img->tagged);
		if(!empty($this->postArr['remove'])){
			$tmp2 = array();
			foreach($tmp as $usr_tmp){
				if($usr_tmp[0] != $usr->id)
					$tmp2[] = $usr_tmp;
			}
			$tmp = $tmp2;
		}else
			$tmp[] = array($usr->id, $usr->name);
		$img->tagged = json_encode($tmp);
	}

	$this->updateObject('jos_igallery_img', array('tagged'), 'id', $img);
	echo $img->tagged;
}

Note the mess we go through with the JSON, I really need to move over to a link table instead… Note that in order to remove a tag we simply call updateTaggedUsers() just like when we add tags with the only difference of $_POST[‘remove’] being non empty.

That was pretty easy wasn’t it, in order to get quick results you just have to find these shortcuts which will spare you the time and pain of having to read some Joomla-, or pick your favorite, CMS book.

Related Posts

Tags: , , ,