2

Getting Module AJAX Events Working in the Front End in LemonStand

Posted (Updated ) in PHP

I had a bit of an issue with this and the documentation wasn’t of much help so I thought I’d post about the process. I currently have CampaignMonitor and MailChimp modules in the LemonStand marketplace and wanted to allow customers to create subscription forms on their sites that AJAX submit.

Firstly, here is the documentation page on custom events. The docs show that you need two things:

  • A subscribeEvents() method in your module’s setup class containing an addEvent() call.
  • A method containing the code you want to execute, which will be triggered by your event.

I attempted to do the above with the following backend code:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class MyModule_Module extends Core_ModuleBase
{
	public function subscribeEvents()
	{
		Backend::$events->addEvent('MyModule_Module:onSubmit', $this, 'on_submit');
	}
 
	public function onSubmit()
	{
		//...
	}
}

And frontend code:

1
2
3
<form onsubmit="return $(this).sendRequest('MyModule_Module:onSubmit')" action="/" method="post">
	<input type='submit' name='submit' value='Submit' />
</form>

I submitted the form and was greeted with an error message:

An AJAX error occurred: AJAX handler not found.

After a little digging I came across the function excuted when you perform an AJAX query. Important lines are highlighted:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static function execAjaxHandler($name, $controller)
{
	$parts = explode(':', $name);
	if (count($parts) != 2)
		throw new Phpr_ApplicationException("Invalid event handler identifier: $name");
 
	$className = ucfirst($parts[0]).'_Actions';	if (!Phpr::$classLoader->load($className))
		throw new Phpr_ApplicationException("Actions scope class is not found: $className");
 
	$method = $parts[1];
	$isEventHandler = preg_match('/^on_/', $method);	if (!$isEventHandler)
		throw new Phpr_ApplicationException("Specified method is not AJAX event handler: $method");
 
	$obj = new $className();
	if (!method_exists($obj, $method))
		throw new Phpr_ApplicationException("AJAX handler not found: $name");
 
	$obj->copy_context_from($controller);
	try
	{
		$result = $obj->$method();
		$controller->copy_context_from($obj);
		return $result;
	}
	catch (Exception $ex)
	{
		$controller->copy_context_from($obj);
		throw $ex;
	}
}

There’s a couple of things to note here.

  • Your second and third arguments in addEvent() are ignored.
  • _Actions is concatenated onto the end of your class name
  • Your method name must start with on_

With the above in mind, it’s time for some rewriting:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
 
class MyModule_Module extends Core_ModuleBase
{
	public function subscribeEvents()
	{
		Backend::$events->addEvent('MyModule:on_submit', $this, 'on_submit');
	}
}
 
class MyModule_Actions extends Cms_ActionScope
{
	public function on_submit()
	{
		//...
	}
}

That worked like a charm. Good luck to all the module developers for LS out there – I’ve found LemonStand a number of quirks like this and we’ll just have to tackle them one at a time 🙂