Using jQuery (or any Javascript library) in Liferay 6.0

 One of the biggest feature requests from Liferay 5.2 was the ability to upgrade the included version of jQuery. Many users would like to use third-party plugins, and most of those require the latest jQuery library (1.4.x as of this writing).

So for 6.0, we solved this a couple of different ways. First, we no longer include jQuery by default. We have rebuilt our UI to run off of AlloyUI which is built on top of YUI3.
By moving off of jQuery, it's also allowed us to step out of the way of developers who wish to  use any version of jQuery that they need without worrying about conflicts with the core portal javascript.
The other way we solved this for the future was by creating our own namespace. Since we're still using a Javascript library (YUI3), we would still have the same risk of conflicts.
So instead of calling YUI() in the portal, we created AUI(). By creating the "AUI" namespace, we are able to guarantee that our environment won't conflict with someone who wants to upgrade their version of YUI3 in the future.
 
But even though we believe strongly in AlloyUI and YUI3, there are existing applications with codebases on jQuery and porting them over is not always possible.
Or perhaps there is some other Javascript library (such as YUI2, Dojo, qooxdoo, ExtJS, etc) that you need to include for the same reason.
 
So today, I want to show a couple of ways to include the third-party javascript library into Liferay that you want. I'll be using jQuery, and I'll be using the URL to their "production" version: http://code.jquery.com/jquery-1.4.2.min.js
 
There are a couple of ways you can include jQuery onto the page.
Jonas has covered a great way in his blog post on building jQuery portlets in Liferay 6.
 
First, using the same basic principle, is including it in your portlet.
In your liferay-portlet.xml add this entry:
<header-portlet-javascript>http://code.jquery.com/jquery-1.4.2.min.js</header-portlet-javascript>
That will add jQuery 1.4.2 onto the page wherever that portlet happens to be rendered.
 
Second, the other way is to add it into your theme. Inside of your theme's templates/portal_normal.vm you would add this line in the head of your theme:
<script src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
This will make jQuery available for everywhere in Liferay, including plugins that you deploy.
 
Third, you can even use AlloyUI to load up other JS files. This is useful if you can't or don't want to edit either the liferay-portlet.xml or the HTML.
 
In any Javascript that gets added to the page, you can do:
AUI().use('get', function(A){

   
   
   
       A.Get.script('http://code.jquery.com/jquery-1.4.2.min.js', {

       onSuccess: function(){
   
   
   
              // jQuery() can be used in here...

      }
 });
});
 
Also, I want to point out that for those people who built apps on Liferay with the version of jQuery that was included (1.2.6), and if you would like to continue to use that version and the plugins that were included by default, we have kept that directory in the source for 6.0 as a deprecated fallback.
 
This allows people who don't want to upgrade the JS portion of their app, they can easily include the previous version.
The way that would look different is that it would just point to the different path, like so:
<header-portlet-javascript>/html/js/jquery/jquery.js</header-portlet-javascript>
The path to the previous version is:
/html/js/jquery/jquery.js and the /html/js/jquery/ directory contains all of the plugins from 5.2 that work with jQuery 1.2.6.
 
I hope that is helpful, and much thanks to Jonas for his blog post about the sample jQuery plugin. And of course, please let me know if there are any questions :)
Blogs
Nice summary, but have some question.

Can you clarify:
"<header-portlet-javascript>http://code.jquery.com/jquery-1.4.2.min.js</header-portlet-javascript>
That will add jQuery 1.4.2 into just that specific portlet."
How it's possible to add jQuery per specific portltet? Is there some scope based Javascript processing in Liferay 6 that hidden somewhere? Because in earlier versions of Liferay header-portlet-javascript always meant that particular script will be included in page where portlet is rendered. So, there were never such (could it be ?) javascript per portlet functionality.
Hi Pavel,
Sorry for the confusion, I will revise that line, because it will add it to the page, but it will only add it when that portlet shows up.
So it's inclusion is bound to the portlet, but it's execution context is not (if that makes sense). We don't do any sort of js sandboxing, though, so I'll correct this to be more clear.

Thanks for pointing this out emoticon
Also is there a standard solution for portet concerning the use of conflicting Javascript library ??

A solution that would allow the portlet to be portable ?

Thanks
Bruno
Hi Bruno,
Much of it depends upon the javascript library itself.
Some libraries, like mootools, prototype, etc, are by their nature conflicting, because they modify the host objects of the browser, and in order to work, they kind of require the ability to modify all of the objects on the page.

If you mean conflicting and multiple versions of jQuery on a page, there is a "standard" way to include multiple versions.

Basically, jQuery has a way to assign itself to a specific variable.

For example:
// Include jQuery 1.2.6
var jQuery126 = jQuery.noConflict(true);
// Include jQuery 1.4.2
var jQuery142 = jQuery.noConflict(true);

Now you have both versions running on the same page. While this is helpful, it's really only useful if neither of those versions include any third party plugins, which we've found is pretty infrequent.
Those third party plugins will be trying to modify a version of the library that doesn't exist.
You could possibly work around this by including your version of jQuery and all of its plugins together, and always followed by a js file like so:

window._myjQuery14 = jQuery.noConflict(true);

That might work out having them on a per portlet basis.
But let me know if you had some other libraries in mind emoticon

Thanks Bruno,
Thanks for your quick reply !

I guess that Portlets cannot do more than what HTML / Javascript is currently capable of. Maybe HTML 6 will allow for easier composition / mashup at the UI level, since it may become more prevalent: http://blog.xebia.com/2010/07/21/service-integration-at-the-presentation-layer/

Regards
Hi Nate,

Yes you are quite right.By using jQuery.noConflict(true) I have implemented so many plugins in the application. But, the problem can be created by third party plugins when they are using jQuery variable in the function call like jQuery.method().

The only solution to that we have to implicitly change the jQuery variable with the name which we have defined using noConflict, say jQuery126 in your example. And that worked for me many times.

Thanks
Krunal Soni
Hi,

I was trying to implement multiple calendars when date picker is clicked. I could easily do it by changing 'numberOfMonths' in ui.datepicker.js in liferay 5.2.3.

But couldn't trace out in liferay 6.0.2. Could you help me?

Thanks,
Ahamed
If more than one portlet uses this

<header-portlet-javascript>http://code.jquery.com/jquery-1.4.2.min.js</header-portlet-javascript>

would inclusion of js file happen only once..

I hope this should be done once once.. else it has no meaning to say it is a global JavaScript.

>That will add jQuery 1.4.2 onto the page wherever that portlet happens to be rendered.

Does this mean, can other portlets on the same page be able to use this javascript, without defining <header-portlet-javascript>http://code.jquery.com/jquery-1.4.2.min.js</header-portlet-javascript>

Assumption here is other portlet is always in the same page portlet A, which does define this script as headder-js..


Regards,
Raja Nagendra Kumar,
C.T.O
www.tejaosoft.com
Nate - I tried using AlloyUI to load up YUI 3.3.0. I basically want to use the new DataTable component. But there seems to be a conflict when using two version of YUI3 on the same page. Any advice on getting around this issue? Thanks.
Tried <header-portlet-javascript>/html/js/jquery/jquery.js</header-portlet-javascript> - the resulting link was /myportlet/html/js/jquery/jquery.js which ofcourse didn't work.

Had to change it to <header-portlet-javascript>/../html/js/jquery/jquery.js</header-portlet-javascript> to make it work, but it feels wrong.

Am I missing something here?
I have a jquery file which i uploaded into js folder but the jruery code in any portal is not working. can u please help me?
"So instead of calling YUI() in the portal, we created AUI(). By creating the "AUI" namespace, we are able to guarantee that our environment won't conflict with someone who wants to upgrade their version of YUI3 in the future"

Nate, can you suggest how to upgrade to YUI 3.3. As we are facing conflicts between YUI 3.2 (which core portal internally uses) and YUI 3.3 (which we are using in our custom portlet).
Nate,

I've been wanting to use a more up to date YUI (particularly the Model/View/Handlebars stuff), just as one other person commented a while back. I wonder if you would comment on the best ways to incorporate later versions of YUI without creating problems in AUI, as it seems that for YUI, things might be a little different than for JQuery and others.

For example, could you comment on (technical parts of ) the answer posted here:
http://stackoverflow.com/questions/7726261/yui-version-conflict-issue-in-portlet