So, when we adopted jQuery, I think I should have done more to evangelize it within Liferay. For most web developers in the world, it's really taken off in popularity because the concept is tied to an existing development paradigm, eg. CSS.
However, that doesn't mean everyone in Liferay is familiar with CSS. But the benefit for the backend folks is that it let's you focus on only having to learn one set of selectors based on an existing and widely supported standard, rather than having to relearn a whole new language paradigm.
So first things first, I'll do a quick lay of the land with jQuery that will help you get up to speed, and then I'll launch into examples that can show you some useful tips that can help you get stuff done today.
First, the concept behind jQuery is that you operate on the DOM (the structure that represents HTML elements on the page).
In normal Javascript development you do everything on the DOM elements directly.
For example:
document.getElementById('banner').style.display = 'none';
document.getElementsByTagName('body')[0].className += ' classic';
Those snippets there find the elements in the DOM, and modify their properties directly. Now, there are a lot of ways to do things like this, and honestly, a lot of them get confusing really quickly. For instance, if you want to change an attribute on an element, some people set the property directly, some people use setAttribute(attr), etc. And every browser has quirks related to this.
So the purpose behind jQuery is to "query" the DOM, and return you back a set of elements (even if its only one element) and operate on that collection.
You can think of every jQuery object as a bucket of DOM elements, and every jQuery method you do on that object is automatically done on every element in the bucket.
One thing commonly done in web dev is to get all elements that match some criteria (querying the DOM), and often, you want to grab everything with a certain class name.
In CSS you would do it like so:
.liferay-element {}
In normal JS you would do it like this:
var allElements = document.getElementsByTagName('*');
var matchedElements = [];
for (var i=0; i < allElements.length; i++) {
var el = allElements[i];
if (el.className.indexOf('liferay-element') > -1) {
matchedElements[i] = el;
}
};
And then you would have your collection of matched elements.
So how would you do this in jQuery?
var matchedElements = jQuery('.liferay-element');
Looks pretty familiar, right?
So now that we have matched elements, what could we do with this? A whole ton of good stuff.
Let's say we wanted to fire an alert box when we click on each of those elements, how would we do it?
matchedElements.click(function(){
alert('you clicked me!');
})
Or what about adding another class to each element?
matchedElements.addClass('new-class');
Or wait, let's say that we have a collection, and we want to make all of them have a red border, BUT, if the element is a span, we want a blue border?
Easy-peasy-lemon-squeezy.
matchedElements.css('border', '1px solid #f00');
matchedElements.filter('a').css('border-color', '#00c');
Notice the filter portion? The filter method reduces a current collection down to a smaller set based on a jQuery selector (or other things, but you can look at the documentation [http://docs.jquery.com] for more info).
So you may be saying "Okay Nate, that's great and all, but you're really boring me here. I don't want to add ugly borders to my elements, and I don't want to hear you ever say that easy-peasy line again, I want to DO STUFF!".
So let's do stuff.
One common thing that we've all done numerous times is use a checkbox to select all checkboxes in a set, sort of a select/deselect all option.
So let's assume we have a group of checkboxes, that don't have a classname, don't have an id, and don't have the same name.
But we know the name attrbiute all starts with the same thing, in this case:
"<portlet:namespace />check"
So, we have our checkbox that acts as the trigger, and but it doesn't start with the same name.
Our example HTML would be this:
<input type="checkbox" id="<portlet: namespace />trigger" /> Here is how we would toggle all of the checkboxes in jQuery:
<input type="checkbox" name="<portlet: namespace />check1" />
<input type="checkbox" name="<portlet: namespace />check2" />
<input type="checkbox" name="<portlet: namespace />check3" />
<input type="checkbox" name="<portlet: namespace />check4" />
var trigger = jQuery('#<portlet:namespace />trigger');
trigger.click(
function(event){
jQuery('[@name^=<portlet:namespace />check]').attr('checked', this.checked);
}
);
So let's go by that, line by line, so we know what we're doing:
var trigger = jQuery('#<portlet:namespace />trigger');
The # sign in CSS signifies an ID, so in this case, we're getting an element by it's ID.
trigger.click(
We're now assigning a click event to our trigger. The events that we add need a function passed in, and the function that is passed in has two special things about it, 1 is that the argument it gets is the event object. I won't go into detail here about what the event object has on it, but it let's you do all kinds of things.
2, however, is that the scope of the function is changed a bit so that "this" points to the element that you're working with. So in this case, this points to the DOM element of our trigger.
function(event){ As mentioned above, here is the start of our function, with the event parameter.
And here is where the magic happens:
jQuery('[@name^=<portlet:namespace />check]').attr('checked', this.checked);
That's kinda nuts right?
Well, jQuery lets you query objects based on parameters, and you can also do minor regular expressions in it. CSS also allows you to do this (in every browser, of course, except IE 6).
It's not a direct port of CSS in this case, but of xpath, in that you have to use the @ sign. The newer versions of jQuery don't require the @ sign, but in Liferay pre-5.1, we have to use the @ sign.
So I'll break this line up:
jQuery('[@name^=<portlet:namespace />check]')
Find every element whose name attribute begins with <portlet:namespace />check. The begins with is done by this part:
^= if we wanted to say every element whos name ENDS with, we would do:
$=
.attr('checked', this.checked) This sets the checked attribute of every element we found to whatever the checked state is of the current element.
So if the current element's checked attribute is set to false (unchecked) all these elements will be unchecked. If it is checked, so will all of those elements.
Okay, but if you ask me, that's kind of a lame example. That's something we've been doing since time immemorial(like since 1999 when Ben Franklin gathered all the animals on the Ark and crossed the Delaware river), and while it's fast, it's not like everyone is screaming "HELP ME CHECK LITTLE BOXES!"
But what if we wanted to do an ajax call on a page that updated a div with the results and show a loading animation so the user isn't wondering what's going on?
Well first, we need to make sure the URL that returning the HTML we need.
Secondly, let's assume the div we want to update has an id of portletBox, and the link we're clicking points to the URL resource, and has an ID of linkTrigger.
Here's our HTML:
<div id="portletBox">
Existing Text is here....
</div>
<a href="http://liferay.com/test/?p_p_state=exclusive" id="linkTrigger">Click me to update our text</a>.
Here's how we'd do it:
var linkTrigger = jQuery('#linkTrigger');
var updateDiv = jQuery('#portletBox');
linkTrigger.click(
function(event) {
updateDiv.html('<div class="loading-animation"></div>').load(this.href);
return false;
}
);
Let's go down a bit at a time:
This of course grabs our elements to work with.
var linkTrigger = jQuery('#linkTrigger');
var updateDiv = jQuery('#portletBox');
Now we'll add a click handler
linkTrigger.click(
function(event){}
This is where we do our work
updateDiv.html('<div class="loading-animation"></div>').load(this.href);
return false;
Let's analyze this a tiny bit. When we click the link, we're first grabbing updateDiv and replacing all of it's HTML with a div that handles the loading-animation.
Right on the end of it, we're doing .load(this.href), which performs an AJAX call and updates the jQuery elements with the results of the AJAX call.
Lastly, we have "return false;". What does this do exactly?
Well, in every browser event, there is a default action. In the case of a link, the browsers default action is to follow the link. However, in our case, we don't want to follow that link, but instead stay on the current page.
When you return false, it prevents the default action from ever taking place.
This also works with every event, for instance, with forms, if you want to do some stuff when you submit the browser, but want to prevent the actual form from submitting, you would return false.
So, that about does it for right now. I'm going to think up some more (useful) examples of things jQuery can do to make your development life a lot easier.
Is there anything you'd like me to cover, for instance, doing animations, or manipulating html elements, etc?

