General developer forum

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

 
 
Picture of Per Ekström
Re: Discussion: Best way of making JS/YUI widgets work with AJAX
 

Ok, I see. That's rather good news, actually. smile

I've been down the road of loading a separate script before, but it's a lot more hassle to maintain and doesn't account for things like, say, being logged out of a session, lazy devs not checking that proper permissions exists (you can write to the database while logged out? WTF?) and other fun things. Therefore I've started to make my own webapps with as few entry points as possible, since it reduces chances of security holes (but at the cost of a slight overhead of course). As you point out, though, it's not a trivial problem to solve.

The biggest advantage to using the $CFG->isajax approach as opposed to AJAX_SCRIPT is that you get all the logic in one place. From there, you can very easily validate all the AJAX output you make to be proper HTML, and it's also fantastic when you turn off JavaScript - everything just works. Because of that, I must say I really prefer doing AJAX pages in this way:

if (!$CFG->isajax) {
    $PAGE->header();
    echo '<p>Hello World!</p>';
    $PAGE->footer();
} else {
    echo '<p>Hello World!</p>';
}

Naturally, this is just a simple example - in reality the Hello World would be a require_once("template.html"), and all the instantiation of the template is done on beforehand. The only disadvantage I can see with this approach is that it requires a bit of juggling with $CFG->isajax, but otherwise I do not see any real drawbacks to the $CFG->isajax approach. But to each to his own, no? smile

From what version is AJAX_SCRIPT available BTW? 2.5 or?

 
Average of ratings: -
Davo
Re: Discussion: Best way of making JS/YUI widgets work with AJAX
Group DevelopersGroup Particularly helpful Moodlers

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)
Picture of Per Ekström
Re: Discussion: Best way of making JS/YUI widgets work with AJAX
 

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"?

 
Average of ratings: -
Picture of Andrew Nicols
Re: Discussion: Best way of making JS/YUI widgets work with AJAX
Group DevelopersGroup Moodle HQGroup Particularly helpful MoodlersGroup 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

 
Average of ratings: -
Picture of Per Ekström
Re: Discussion: Best way of making JS/YUI widgets work with AJAX
 

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!

 
Average of ratings: -