Frank Ralf (talk | contribs) |
|||
Line 147: | Line 147: | ||
</code> | </code> | ||
Unfortunately, .preventDefault() will usually not work across browsers with normal JavaScript due to different implementations of the Event object. But jQuery does some standardizing under the hood to provide cross-browser compatibility for most Event properties and methods. | Unfortunately, .preventDefault() will usually not work across browsers with normal JavaScript due to different implementations of the Event object. But jQuery does some standardizing under the hood to provide cross-browser compatibility for most Event properties and methods, see [http://docs.jquery.com/Events/jQuery.Event#event.preventDefault.28.29. event.preventDefault() ]. | ||
== See also == | == See also == |
Revision as of 12:18, 27 July 2009
YUI vs. jQuery - The big challenge!
"If you really want to convince me, I would like to see a conversion of http://cvs.moodle.org/moodle/user/selector/script.js?view=markup (it is used on the assign roles and add group members pages). That is a serious application of JavaScript. However, that is also a lot of code, so it is not really fair to ask for a conversion just as a proof of concept."
--Tim Hunt 04:52, 21 July 2009 (UTC)
- Look Frank Ralf/JavaScript1 for the background for this challenge...
- Feel free to add comments on the talk!
- We will tackle this big task step by step ...
- The examples were tested with FF3 and IE6 to check for cross-browser compatibility.
AJAX based selecting of users
Screenshot
For those who don't have a current installation of the brand new Moodle 2.0 at hand here's a screenshot so you get an idea what this is all about:
While you are entering text in the search field the database is queried in real-time in the background for matching users. This is done using AJAX without any page re-loading required.
For comparison here's the same page with JavaScript turned off:
The underlying code
- This feature is provided by the use of YUI features in the file user/selector/script.js.
- It was inspired by YUI's AutoComplete control.
- It uses YUI's DataSource utility for the database connection.
Getting ready for jQuery
If you want to play along you first have to add jQuery to your Moodle installation. Just download the library (56 KB) and copy it into the /user/selector folder. Then you add jQuery to the list of required JavaScript in /user/selector/lib.php:
// Required JavaScript code.
$PAGE->requires->yui_lib('json');
$PAGE->requires->yui_lib('connection');
$PAGE->requires->yui_lib('datasource');
// Adding jQuery before other JS files of the module
$PAGE->requires->js('user/selector/jquery-1.3.2.min.js');
$PAGE->requires->js('user/selector/script.js');
A) DOM manipulation - moving, adding and deleting HTML elements
A very common task when using JavaScript for modifying HTML is moving, adding and deleting HTML elements. So that's where we will start our venture.
The task
Following the principle of Unobtrusive JavaScript the form must also be usable with JavaScript turned off.
So without JavaScript the form contains a search field and two submit buttons: one for executing the search and one for clearing the search field. Clicking any of those two buttons triggers a request to the server which will execute the function and sends a new page back to the browser.
Without JavaScript |
---|
For the AJAX version the search is done automatically and asynchronously (remember the "A" of "AJAX") while typing in the search field. Therefore the form should not be sent and the search button will be replaced by a simple label which will be placed to the left of the search field. This is the first task we will tackle.
AJAX version |
---|
The current solution
Here's the original code. We're creating a label, inserting it before the search field and then delete the search button.
// Hide the search button and replace it with a label.
var searchbutton = document.getElementById(this.name + '_searchbutton');
var label = document.createElement('label');
label.htmlFor = this.name + '_searchtext';
label.appendChild(document.createTextNode(searchbutton.value));
this.searchfield.parentNode.insertBefore(label, this.searchfield);
searchbutton.parentNode.removeChild(searchbutton);
You might be wondering why there's no sign of YUI. Well, YUI hasn't entered the ring yet. It might come as a surprise, but YUI's DOM utility doesn't provide any methods for creating and moving HTML elements. YUI's Element utility provides rudimentary support, but most of the time we have to resort to JavaScript's build in methods, which are not the most intuitive. - Some consider this a feature, not a bug, though. ;-)
The jQuery solution
jQuery on the other hand provides a whole bunch of methods for manipulating the DOM tree. So we can accomplish the same task with the following code.
Note that the order of the steps is slightly different from the above version:
Here we
- take the search button,
- insert it before the corresponding search field,
- and then replace it with a label with the same text as the search button.
var searchbutton = document.getElementById(this.name + '_searchbutton');
$(searchbutton)
.insertBefore(this.searchfield)
.replaceWith('<label>' + searchbutton.value + '</label>');
B) Modifying the Clear button
After catering for the search button, the Clear button is next on our list. This time we can't get rid of the button altogether because we still need its function also in the AJAX version.
The current code
// Replace the Clear submit button with a clone that is not a submit button.
var oldclearbutton = document.getElementById(this.name + '_clearbutton');
this.clearbutton = document.createElement('input');
this.clearbutton.type = 'button';
this.clearbutton.value = oldclearbutton.value;
this.clearbutton.id = oldclearbutton.id;
oldclearbutton.id = ;
oldclearbutton.parentNode.insertBefore(this.clearbutton, oldclearbutton);
oldclearbutton.parentNode.removeChild(oldclearbutton);
The task
On first glance this resembles the first task: replacing the Clear button with something else. But wait, why replacing it with another button that looks exactly like the original one? The only difference is that the clone is not a "submit" button (<input type="submit" />) but a simple "button" (<input type="button" />).
What's that good for? Well, the purpose is to prevent the button from sending a request to the server when being clicked, which is the default behavior for submit buttons. In the AJAX version, we instead apply our own click handler to the Clear button and clear the search field with client-side code alone. So we have to look at the above code snippet in conjunction with the click handler for the Clear button:
// Hook up the event handler for the clear button.
YAHOO.util.Event.addListener(this.clearbutton, "click", function(e) { oself.handle_clear() });
- I am pretty sure this is the first thing I tried, and it did not work reliably cross-browser. The only option was to throw away the old button and make a new one. However, I don't remember the details now, an they don't seem to have been preserved in CVS.--Tim Hunt 09:41, 27 July 2009 (UTC)
The jQuery solution
With jQuery we don't have to clone the Clear button. We instead leave it as it is (as a "submit" button) but prevent the sending of a request to the server by using the DOM method .preventDefault() on the click event we attach to the Click button:
this.clearbutton = document.getElementById(this.name + '_clearbutton');
$(this.clearbutton).click(function(event){
oself.handle_clear();
event.preventDefault();
});
Unfortunately, .preventDefault() will usually not work across browsers with normal JavaScript due to different implementations of the Event object. But jQuery does some standardizing under the hood to provide cross-browser compatibility for most Event properties and methods, see event.preventDefault() .