Discussion: Best way of making JS/YUI widgets work with AJAX

Re: Discussion: Best way of making JS/YUI widgets work with AJAX

by Davo Smith -
Number of replies: 3
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

AJAX_SCRIPT has been there since Moodle 2.0 (unless I'm mistaken).

You might want to consider the following variation on your AJAX page:

ajax-page.php:

define('AJAX_SCRIPT', true);
require_once('../../config.php');
require_once('lib.php');
myclass::view();

view.php:
require_once('../../config.php');
require_once('lib.php');
...
echo $PAGE->header();
myclass::view();
echo $PAGE->footer();

lib.php:
class myclass {
  public static function view() {
     echo html_writer::tag('p', 'Hello world!');
  }
}

By routing most of your logic through a class in a library file, you eliminate many of the problems of multiple entry points, whilst retaining much of the code clarity that comes from them.

 

Average of ratings: Useful (2)
In reply to Davo Smith

Re: Discussion: Best way of making JS/YUI widgets work with AJAX

by Per Ekström -

Yes, absolutely, you can do it that way (and I did for quite some time). My experience with doing it that way, however, is that you're far better off trying to minimize your entry points to your apps. Separating the logic from the presentation helps, a bit, but what happens when you for instance try to make an AJAX call to a script supposed to output JSON when you're logged out? You do get breakage, and it's a bigger risk that edge cases causes breakage. That's the primary reason I'm not really fond of multiple entry points.

In the end it's a matter of preference though and both styles have their advantages as well as their disadvantages. But, shouldn't it be possible to do something like:

if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'xmlhttprequest' OR optional_param('isajax',0,PARAM_BOOL)) {
    define('AJAX_SCRIPT',true);
}

[...]

if (isset(AJAX_SCRIPT)) {
    myclass::view();
} else {
    $PAGE->header();
    myclass::view();
    $PAGE->footer();
}

Couldn't that combine both into one "best of both worlds"?

In reply to Per Ekström

Re: Discussion: Best way of making JS/YUI widgets work with AJAX

by Andrew Lyons -
Picture of Core developers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers Picture of Testers

Hi Per,

I considered this too. Ignoring the fact that you wouldn't be able to use optional_param (because it's not available until config.php is defined, by which time it's too late to define AJAX_SCRIPT), this can work. I had a play with a proof-of-concept adding the code to lib/setup.php.

I felt at the time that it was still better in some respects to keep the entrypoints separate as this could lead to confusion later on. It's too easy to expect AJAX_SCRIPT to do all of the formatting too, and that may be the case, but chances are that it won't. Although some people will write their code as you suggest, there's a strong chance that people will do a lot of testing AJAX_SCRIPT all over the place in the same script, and will lead to nastier code to read.

Keeping the AJAX version in a separate script, appropriately namespaced, gives a clear indiciation as to purpose.

Perhaps it's worth re-opening the debate though... what are your main reasons for disliking multiple entrypoints?

Andrew

In reply to Andrew Lyons

Re: Discussion: Best way of making JS/YUI widgets work with AJAX

by Per Ekström -

Hi Andrew!

Sorry for being a timesink, I'll try to keep this brief.

The main advantages and disadvantages to single- vs multi entry points the way I see it are these:

Single entrypoint

Advantages

  • Less risk of security holes and edge-case bugs
  • Opens up for automatic testing and/or (X)HTML validation
  • Everything collected in one place, easy to follow and overlook
  • Almost impossible to break the "No JavaScript Requirements" rule
  • All links can go to "real" places with little to no extra work, thus not breaking middle-clicks
    • Compare <a href="view.php?id=14" onclick="load_ajax('foo',this.url+'&isajax=true')">this link</a> with a classic <a href="#" onclick="load_ajax('foo','ajaxscript.php')">ajax link</a>

Disadvantages

  • Not as efficient, intuitive or straightforward as multi-point
  • Source code files can get large, complex and hard to overlook, especially with multiple paths
  • Does require a bit of "PHP logic juggling", especially if you want automatic test benefits

Multiple entrypoints

Advantages

  • Clear purpose
  • Simple structure - one-script-does-everything
  • Fast and efficient - All unneccessary fat trimmed away

Disadvantages

  • Need to be very careful about logic in order to avoid security holes
  • Error handling might miss edge cases, which might give the user a bad impression
  • Hard to automate tests and automatic (X)HTML validation
  • Code can get rather complex - ajaxscript.php calls to ajaxscript2.php which calls to a template file that calls to ajaxscript3.php etc etc
  • Might possibly break the "No JavaScripts required" rule

Do note that many of the advantages/disadvantages I list are dependant on how you break up your code, and my bad experiences with multi-point may have clouded my judgement. In either case you need a solid structure and a steady hand, else you'll just end up with the old-fashioned PHP soup we've both seen once too many times... smile

Hope that made it a bit clearer on my position!