Profile

Recent Bloggers

Neil Griffin Posts: 20
Stars: 59
Date: 7/30/10
Jorge Ferrer Posts: 34
Stars: 157
Date: 7/30/10
Alice Cheng Posts: 155
Stars: 13
Date: 7/29/10
Ronald Sarayudej Posts: 118
Stars: 275
Date: 7/29/10
Stephen Wilburn Posts: 1
Stars: 3
Date: 7/28/10
Samuel Liu Posts: 3
Stars: 2
Date: 7/27/10
Juan Fernández Posts: 8
Stars: 22
Date: 7/26/10
Ray Augé Posts: 46
Stars: 201
Date: 7/24/10
Brian Chan Posts: 33
Stars: 214
Date: 7/23/10
Nate Cavanaugh Posts: 33
Stars: 115
Date: 7/20/10

Blogs

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 :)
AlloyUI - Working with Widgets, Part 1

 What is an Alloy widget?

A widget is something that does some sort of task. Like what, you might ask? For instance, in Alloy, there's a TreeView widget, where you can configure it to display an hierarchy of data, and this hierarchy can be ajaxed in, or shown right away, and with a lot of different options.
That would be a pretty complex widget.
A simple widget would be the Tooltip widget, which just shows users some content when they hover over an item on the page.
 
In Alloy, there's a large collection of widgets, as well as a robust framework for building your own.
 
In this blog post, I'm going to cover some of the widgets that we have in Alloy, then in the next one, I'll post how to create your own. I'm splitting it up because I'm finding both posts have a lot of info to cover, and I don't want people to zone out or miss info they might have found useful because it was buried in a super long post.
 
So let's go ahead and get our sandbox ready:
 
AUI().use('', function(A){
 // Our code will go here
});

I'll reference the name of the widget above the code so you can see the module that we'll be using in order to run it.
 
So let's go ahead and create a TreeView of a user directory that has drag and dropping of elements, and expandable folders.
 
Here's the demo: TreeWidget
Here's the code you would have to write:
 
You would use the aui-tree-view module
 
var users = new A.TreeViewDD({
     children: [{
           label: 'Users',
           expanded: true,
           children: [{
                label: 'Nate Cavanaugh',
                expanded: true,
                children: [
                     {label: 'Documents', leaf: false},
                     {label: 'Downloads', leaf: false},
                     {label: 'Movies', leaf: false},
                     {label: 'todo_list.txt'}
                ]
      }]
 }]
}).render();
 
Let's look at what's going on here. First we're doing a traditional object construction in JavaScript, which is creating a new object. You're saying give me a new TreeView, and let's call it "users".
 
So what's with that .render() at the end?
 
That render() does not have to be called until you're absolutely ready to display the widget. In fact, there are many times where you may wish or need to configure a widget, but only render it under certain circumstances, or after a certain period of time has passed.
 
But if you don't care about waiting, you can just do it all inline (render will still return a reference to the widget).
 
We've just created a tree widget, and have this users variable, so what? Why is this exciting if you're just *using* widgets?
 
Because even if you're just using widgets, you can still do VERY interesting stuff with these widgets. Remember how we talked about working with elements?
 
The widget API is VERY similar to the Node API, meaning that in the same way that you can do get/set for properties on a Node, you can also do that on a Widget. And in the same way that you can use .on() for nodes, you can also do the same thing for Widgets.
 
But before we jump into that, let's look at another widget, something like Tooltip.
 
So let's go ahead and create a Tooltip. We'll use the aui-tooltip module:
var tooltip = new A.Tooltip({
     trigger: '.use-tooltip',
     bodyContent: 'Hello World!'
}).render();
 
What we're doing here is saying give us a new Tooltip, and show it when you hover over any item with the css class of .use-tooltip. It's also saying to show the content of the body to be "Hello World!". Now, in most cases, this wouldn't be super helpful because you wouldn't want to have the same tooltip text for multiple items, but there is a way to easily have it read the title attribute of the element instead. I'm simply manually using the bodyContent to illustrate the next part.
 
So now we have our tooltip object, what can we do to it? Well, all of those things we passed into it, like trigger, and bodyContent can all be read or changed using get/set, and not only that, but you can listen in to when they're changed as well.
 
This might take a second to realize just how cool this is, but take my word for it, it's insanely powerful.
 
Let's take a look. We'll go ahead and change the message of the tooltip to instead say "Hey there Earth!".
 
tooltip.set('bodyContent', 'Hey there Earth!');
 
Now when you hover over it, the tooltip will say 'Hey there Earth!'.
 
Moderately cool, but the real power comes from the change events that are used with this. Whenever you use get or set, the widget fires a custom event for that change.
So in this case, the event that got fired was "bodyContentChange". Every attribute on the widget fires a "change" event when it gets changed, and you can listen to it in two phases.
 
You can basically listen to the attribute get changed before the value is changed, and prevent it if you want, or after it gets changed.
 
This took me a few minutes to sink in, but here are the benefits:
 
Even as a person using the widgets, you have the ability to listen to interesting moments of what's going on and manipulate widgets on the page.
 
Here's an example: 
All widgets have an attribute called "visible", and when this attribute is changed, the widget hides or shows. Usually you just call widget.hide() or widget.show().
 
But let's say on our tooltip, we want to listen before it shows, and if a certain element is missing on the page, we will prevent the tooltip from being shown.
 
We would do:
 
tooltip.on('visibleChange', function(event){
     if(!A.one('#myEl')){
         event.preventDefault();
     }
});
So now, the tooltip will only show up if an element with the id of myEl is on the page.
 
Or here are some more practical examples:
 
Let's say you're creating a Dialog, and you toggle the visibility of the dialog based on if a separate ButtonItem widget is active?
 
You would use the aui-button-item widget, and the aui-dialog widget, and do:
 
var dialog = new A.Dialog({title: 'Hello', bodyContent: 'Lorem Ipsum'}).render();
var buttonItem = new A.ButtonItem({active: true, label: 'Toggle Dialog'});

buttonItem.after('activeChange', function(event){
 dialog.set('visible', event.newVal);
});

Or what about if you have a ColorPicker widget, and want to update the value of a text input when the hex code changes? You can even pass in the events when you create the widget.
 
You would use the aui-color-picker
 
new A.ColorPicker({
     after: {
         hexChange: function(event){                             A.one('#myInputNode').val(event.newVal);

         }       } }).render();
Another thing I mentioned last time was that Widgets can be plugged just like Nodes. Well, remember our handy dandy IO plugin? We can plug any widget with it, and it will automatically know what elements it should grab internally.
 
For instance, let's create another dialog again, and let's plug it: 
var dialog = new A.Dialog({title: 'Hello World'}).plug(A.Plugin.IO, {uri: 'test.html'}).render();
The plugin will smartly grab the area where the content goes, but not the area of the titlebar, and add a loading mask, and insert the content of the ajax request into there.
 
A couple of notes:
 
The .render() method, will, by default, add the widget into the body element. But if you pass it either a selector or a element, it will render the widget into that element on the page.
 
So I could have easily done this:
new A.ColorPicker().render('#myContainer');
 For Widgets, if you attach a listener "on" that event, it fires before the change has been made, so you can think of it as a "before" stage. It's kind of confusing, but it works.
If you listen to the "after" stage, it's after the work has already been done.
In most cases, you'll only care about being notified after, unless you want to prevent something from happening, or want to know before it happens.
90% of the time, I use "after" to listen to widget events.
 
Anyways, that's it for now on using the widgets. Next time, we'll talk about how you can make your own widget, and what a widget is actually made of.
See you then!
AlloyUI - Working with Plugins

 I mentioned last time that I would talk about the IO Plugin that we have that makes one of the most common tasks of updating content.

So first, I'll show you how to use it, then we'll talk more about how to make your own plugin.
 
So let's set up our sandbox:
AUI().use('io-plugin', function(A){
 // Our code will go here
});
 
So the IO plugin is essentially everything that A.io.request is. All the same arguments, same behavior, but what it does for you is kinda cool.
 
There is a common pattern we kept seeing in our ajax calls which was:
 
  1. Insert loading icon into region
  2. Do ajax call
  3. On success, update region with new content
Here is what the code would look might like before:
 
var contentNode = A.one('#contentNode');

if(contentNode) {
  contentNode.html('<div class="loading-animation"></div>');

  var myRequest = A.io.request('test.html', {
    on: {
      success: function(event, id, xhr) {
        contentNode.html(this.get('responseData'));
      }
    }
  });
}

It's a trivial process, but when you see it so often, you start to think that it's one of those patterns that could imagine yourself sitting in a padded room chanting over and over.
 
So we created a handy little plugin that handles this for us, and in a much nicer way. What this plugin does is does an ajax request the same as A.io.request, but also adds a loading mask to the area that we want to load content into. As soon as the content is ready, it parses through it and looks for any javascript that may be inside of it and executes it, and sets the content into our area.
 
var contentNode = A.one('#myNode');

if(contentNode) {
 contentNode.plug(A.Plugin.IO, { uri: 'test.html' });
}
And that's it.
 
Here's what it looks like:
 
It basically will mask any existing content, and add a loading indicator that is centered above it.
 
Here is some of the cool stuff about the plugin (and all plugins in Alloy):
 

1. It has it's own namespace

This means that this plugin lives inside of it's own area on the node so that it won't clobber with other plugins. Here's a good reason. A.Plugin.IO inherits all of the methods and properties that are on A.io.request, so you can call things like .start(), .stop() (to start and stop the request of course), or .set('uri', 'new_test.html'), or .set('dataType', 'json') and everything else we covered in the <a href="http://www.liferay.com/web/nathan.cavanaugh/blog/-/blogs/alloyui-working-with-ajax?_33_redirect=%2Fweb%2Fnathan.cavanaugh%2Fblog">last post</a>.
If all of that was placed on the main object, then it would conflict with any methods that might exist already on that node, or maybe another plugin.
So instead, it's placed in a namespace, and you can access that like so:
 
contentNode.io
 
So if you want to set the dataType on the plugin to json, you can do:
 
contentNode.io.set('dataType', 'json');
or if you want to stop the connection:
contentNode.io.stop();

2. Plugins can be "unplugged"

This is incredibly useful if you're writing a plugin that should do some clean up work when a user is finished with it (for instance, if you have a plugin that adds in some children elements or adds on some class names to a container).
 
You would just call:
contentNode.unplug(A.Plugin.IO);
 

3. Plugins can be plugged to NodeLists as well as Nodes

So this would work as well:
 
var contentNodes = A.all('.content-nodes');

contentNodes.plug(A.Plugin.IO, { uri: 'test.html' });
 
Then we could grab the first item in the NodeList and access the plugin namespace
contentNodes.item(0).io.set('cache', false);
 

4. Plugins can also be on Widgets

I'll cover widgets more next time, but the same exact process applies, and in fact, the IO plugin is written in such a way that it knows whether it's in a Node or a Widget and will behave accordingly.
 

5. Plugging doesn't have to be a per instance affair.

You can do this:
A.Node.plug(A.Plugin.IO, {autoLoad: false, uri: 'test.html'});
Now you could do:
var contentNode = A.one('#contentNode');
if(contentNode) {
 contentNode.io.start();
}
 
The difference is that since we called A.Node.plug() (which is a static method on the Node class), it plugs all newly created instances with that plugin.
 
I recommend doing it on a per instance basis, however, simply because 1, you'll consume less resources, and two, you don't have to worry about if your existing objects have been plugged.
 
6. You can plug with multiple plugins at once.
So for instance, you can do this:
 
contentNode.plug([
 { fn: A.Plugin.IO, cfg: {uri: 'test.html'} },
 { fn: A.Plugin.MyOtherPlugin }
]);
If that looks confusing, feel free to ignore it, but it simply is a way to pass in mutliple plugins and their configurations (if they need one) all at once.
 

Creating a plugin

 
What's the simplest way to get started creating a plugin? Well here's what's to remember: A plugin, at the very least, is a function, with a property on it called NS which will be it's namespace.
 
So for this example, I'm going to create a plugin that takes an input field, and inserts a "defaultValue". When you focus the field, if the value matches the "defaultValue", it will empty the field, and allow the user to enter their value. When the user moves away from the field, if they haven't entered anything new, it will add in the default text.
 
If you wish to jump to the demo, go ahead and take a look here: Plugin Demo.

 

 
I'm going to start with this markup:
 
<input data-defaultValue="Enter Text" id="myInput" type="text" value="" />
 
HTML5 allows for custom attributes if you prefix the attribute with "data-", so you'll notice I added a new attribute called "data-defaultValue", which our plugin will read.
 
So I'll create the javascript:
 
var defaultValuePlugin = function(config) {
    var node = config.host;

    var defaultValue = node.getAttribute('data-defaultValue');
    var startingValue = node.val();

    if (!startingValue) {
      node.val(defaultValue);
    }
    node.on('focus', function(event) {
      var value = node.val();

      if (value == defaultValue) {
        node.val('');

      }

    });

    node.on('blur', function(event) {
      var value = node.val();

      if (value == '') {
        node.val(defaultValue);

      }
 });
};

defaultValuePlugin.NS = 'defaultValue';

Now all we have to do to get it working is simply plug it onto a node:
 
A.one('#myInput').plug(defaultValuePlugin);
 
I'll go over some points of the code above.
 
One is that, notice that the first line points to config.host. The argument config is the configuration object that is passed into the plugin, but by default the host is always passed into the plugin, so you always have access from the plugin to whatever is being plugged.
It's like a magic link to whatever item you're plugging.
 
The next lines I'm doing the basic work getting an attribute, setting a value if one hasn't been set, and in the bulk of it, attaching focus and blur listeners to do the checking for the value.
 
On the last line, I'm attaching a property called NS to the function that we created. This is the namespace that this plugin will live under, and even if we don't need to access anything specifically, it's there so we can plug something without worrying about it colliding with any other plugins.
 
This is really just scratching the surface of the power that the plugin system offers, but I wanted to show a simple case, rather than bog down in the mire of complexity. If there is any interest in seeing advanced plugins, I can always write an 11th blog post, but the YUI3 page also offers a lot more info if you would like to investigate further as well.
 
Until next time, see you guys later!

 

AlloyUI - Working with Ajax
Ajax is one of those patterns that are a must have with a UI framework, so let's go ahead and jump right into doing some Ajax requests, and then we'll dive into the more complex cases.
 
Let's prep our sandbox, but this time, the module we're going to use is called "aui-io-request".
 
AUI().use('aui-io-request', function(A){
 // Our code will run here
});
 
The simple of the simple, let's assume we're just going to be making a simple ajax request to a plain html file, called "test.html".
 
A.io.request('test.html');
 
That's all there is to it. However, that's not very interesting because it doesn't do anything.
 
Let's say want to send a POST request to the server:
 
A.io.request('test.html', {
   method: 'POST',
   data: {
     key1: 'value'
   }
});
 
How about responding to the server? There are 5 possible callbacks: start, complete, success (or) failure, and end.
 
If I wanted to alert the response from the server, here's what I would do: 
A.io.request('test.html', {
  on: {
   success: function() {
     alert(this.get('responseData'));
   }
  }
});

What is this.get('responseData')? It's basically a normalized property of what is returned from the server. It's useful because A.io.request supports having different types of data returned by the server and automatically handled.
For instance, if your server returns JSON like {"myProperty": 2}, you could do something like:
 
A.io.request('test.html', {
  dataType: 'json',
  on: {
   success: function() {
     alert(this.get('responseData').myProperty); //alerts 2
   }
  }
});
 
You can also work with XML that way. Assuming your server returns something like: <name>AlloyUI</name> you could do:
A.io.request('test.html', {
  dataType: 'xml',
  on: {
    success: function() {
     alert(A.all(this.get('responseData')).all('name').text()); // alerts AlloyUI
    }
  }
});

You can also submit all of the data in a form via ajax as well. Here's the simplest version: 
A.io.request('test.html', {
  form: {

      id: 'myFormId'

  }
});
 
That will serialize all of the data in the form, and send it to "test.html".
 
One other handy feature of this is that you can define an ajax connection once, and reuse it multiple times, and start and stop it later on.
Here's an example: 
var myAjaxRequest = A.io.request('test.html', {
    method: 'POST',
    data: {
      key1: 'value1'

    }

});

Now later on, if I want to make that same ajax call again, all I have to do is call:
 
myAjaxRequest.start();
 
But what if I want to just define the call, but not execute it the first time (for instance, you know you want to run it later, but you don't want to update the server), you can do:
 
var myAjaxRequest = A.io.request('test.html', {
 autoLoad: false,
 ...
});
 
What's cool about this is that if later on, you want to change one of the properties before you send the request, you can do that as well. For instance, let's say you want to disable caching before you start the connection again:
 
myAjaxRequest.set('cache', false);
 
Or if you wanted to change from POST to GET
 
myAjaxRequest.set('method', 'GET');
 
Or change the dataType to JSON:
 
myAjaxRequest.set('dataType', 'json');
 
Or even change the URI at the last moment:
 
myAjaxRequest.set('uri', 'new_test.html');
 
Then when you're ready you would call:
 
myAjaxRequest.start();
 
And if at any time after you have started the request, you want to stop the whole request, you can call:
 
myAjaxRequest.stop();
 
And that's most of it right there. There are some cool plugins that we have that make working with ajax easier, but since the next topic is on plugins, I'll cover those in the next blog post, and they'll be a nice segue between topics.
 
One of those plugins is called A.Plugin.IO, and it's incredibly awesome, because it simplifies the extremely common task of not only loading content into a node or a widget, but adding a loading indicator to that node and automatically parsing the javascript for you.
 
I'll go into more details in the Plugins post, but it's really handy.
 
See you then!
AlloyUI - Working with elements and events

Getting Started

Welcome to our first post in talking about Alloy. I'm going to jump right in, but the only piece of info I want to cover beforehand, and you'll see me do it in every post, is the idea of "sandboxes". Because AlloyUI is built on top of YUI3, it has the concept of the sandbox. What this means is simply a callback where you run your code.

The way it's constructed is that you declare the packages that you want to use, and then, inside of your sandbox, you use them.

The benefit to this is that it allows your code to run as lean as possible, and loading only what it needs, without having to load a lot of stuff on the page first.

How do you create a sandbox?

Simple:

AUI().use(function(A) {   // Your code goes here  });

Let's look at that real quick.

AUI() is a function call, and you attach a .use on it. Inside of that .use(), you can pass 1-n number of arguments, but the last argument *must always be a function*.

You'll notice that the callback gets an argument passed to it called "A". That A is *the* Alloy object. It's where all of Alloy objects and classes are stored.

 

Most of the time you'll be setting up your sandbox using at least one or two packages. Here's how that would look like using the event and node packages:

AUI().use('event', 'node', function(A) {
   // Your code goes here
});

When you see me write code samples where I do something like:

A.one('body');

assume that I am inside of the sandbox.

Working with elements and events

The most common task you're most likely to come across in web development is working with elements on the page, and doing something with them. AlloyUI, because it's built on top of YUI3, has two objects for working with elements on the page, Node and NodeList. These two objects are closely related, and in fact, you can think of them as almost the same. The only difference is that Node is a single item, and NodeList is a collection of Nodes.

There are two methods you can use to get elements on the page, and each will return something different depending on the method.

The methods are called A.one() and A.all().

A.one() will return a Node object if it finds the element on the page (null otherwise), and A.all() will always return a NodeList (if it doesn't match any elements, it will return an empty collection).

 

Here's a few examples of how A.one() would be used:

var el_1 = A.one('#myCustomElement1');

var el_2 = A.one('.custom-element');

var el_3 = A.one('input[type=checkbox]');

Notice how A.one() will accept selector strings that are not just for ID elements? What if there are multiple elements matching the selector? It will just return the first one. This is useful in many situations, and has an impact on performance.

If the selector cannot be matched on the page, then A.one() will return null. This means that in order to operate on the Node element, you have to first do an if check on the variable then do the work.

For instance:

var el_1 = A.one('#myCustomElement1');

if(el_1) {

 el_1.setStyle('height', 50);

}

This can seem a bit verbose to some people, so it could be avoided if you wish. You could write the above like so:

A.all('#myCustomElement1').setStyle('height', 50);

without risk of throwing an error.

So why do I prefer A.one()? Mainly because of performance. A.one() will run about 2-4x faster to grab the element, but it also helps me write out clearer code (I know that if I'm not updating a block of code it's because it didn't find an element, whereas trying to debug long chains of code is a nightmare).

But both methods are there for you.

What kind of selectors are available? By default, anything in CSS2, which covers 98% of the cases and most of the selectors I've needed to write.

However, there is a CSS3 module, and if you need to do something like:

A.all('.custom-element > div:nth-of-type(even)'), just add the "selector-css3" module to your sandbox, and the selectors are available to you.

It's pretty rare that we've actually *needed* these selectors, though, but again, they're there if you need them.

That covers the basics on getting the elements, what about doing something with them?

So, let's cover some common tasks:

Setting styles

I'm going to grab my element:

var nodeObject = A.one('#myElement');

Setting a background color:

nodeObject.setStyle('backgroundColor', '#f00'); //Sets the background color to red

Setting a border 

nodeObject.setStyle('border', '5px solid #0c0'); //Sets a large green border

But what if I want to set multiple styles all at once? Just simply use the setStyles method (notice the "s" on the end of the name?).

nodeObject.setStyles({
   height: 200,
   width: 400
});

You can also get the current style for an element by doing something like:

nodeObject.getStyle('border');

One common task I think we've all done is to try to position a box somewhere on a page? Usually we'll just set the styles on the element, including the positioning.

For instance, let's say we wanted to move something to exactly 100px from the left, and 200px from the top.

Usually we might do something like:

nodeObject.setStyles({
  left: 100,
  position: 'absolute'
  top: 200
});

But then, what happens if it's inside of a positioned container? It will be relative to the container, then your offset will be off.

Instead, here's how you would do it now:

nodeObject.setXY([100, 200])

And it will automatically calculate the parents positioning for you guaranteeing that it's at the spot absolutely on the page that you want it. Much shorter code and much more accurate.

But what is really cool that is related to this is, often times you just want to center an item on the page absolutely. Here's how you would do it:

nodeObject.center();

Working with class names

All of the most convenient ways of working with class names, and then some, are here:

nodeObject.addClass('custom-class');

nodeObject.removeClass('custom-class');

nodeObject.toggleClass('custom-class');

nodeObject.replaceClass('custom-class', 'new-class');

nodeObject.hasClass('custom-class');

nodeObject.radioClass('custom-class');

In that last line, radioClass() will remove the class name from all of the sibling elements, and add it only to the current item, similar to how a radio button would behave.

 

Manipulating elements

Appending a new element to the nodeObject:

nodeObject.append('<span>New Text</span>');

Appending the nodeObject to another element already on the page:

nodeObject.appendTo('body');

Updating the innerHTML of an element:

nodeObject.html('<b>new text</b>');

Removing an element:

nodeObject.remove();

Creating a brand new node from scratch:

var newNodeObject = A.Node.create('<div id="myOtherElement">Test</div>');

Moving up and down the elements

Often you need to jump around to different elements relative to the current one you're on (for instance, to find a parent of a current item or a child/children).

Finding the first parent of nodeObject with the class name of .custom-parent:

nodeObject.ancestor('.custom-parent');

Finding the first child with the class name of .custom-child:

nodeObject.one('.custom-child');

Finding all children with the class name of .custom-child:

nodeObject.all('.custom-child');

It's interesting to note that most of the methods that are on Nodes are also on NodeList. The ones that aren't are usually just the getters where it wouldn't make sense for a collection of items to return the data from any one item.

Meaning this: it makes sense to have a collection, like nodeListObject, which contains 5 div elements, and when you call nodeListObject.setStyle() for that style to be applied to all 5 elements, or if you call nodeListObject.append('<b>test</b>') for it to append a new b element to every item.

But it doesn't make much sense to do: nodeListObject.getStyle('backgroundColor'). What should it return? The first item in the collection? The last item?

And since it's insanely easy to do this instead:

nodeListObject.item(0).getStyle('backgroundColor')

it just makes more sense not to add the methods onto the NodeList to avoid confusion when getting data out of an element.

Getting properties

Now, here comes a really interesting part. Since nodeObject is a wrapped element, you can't just do nodeObject.id to get the id or nodeObject.parentNode. If you tried that, it would return undefined.

Instead, we do nodeObject.get('id') or nodeObject.get('parentNode').

Here's what is REALLY cool about using the getter: nodeObject.get('parentNode') will return another wrapped Node object, and if it's a collection, like nodeObject.get('childNodes'), it will be a wrapped NodeList object.

So all of the DOM properties are available.

EVEN cooler:

get will accept a dot (.) separated list of properties and traverse it for you. So let's say you know you have an item exactly three parents up, and want to set the background color to red:

nodeObject.get('parentNode.parentNode.parentNode').setStyle('backgroundColor', '#f00');

Interaction time

We've touched on how to wrangle the elements on the page. What about adding an event to it, such as doing something when a user interacts with it?

It's actually pretty simple. Every Node and NodeList has a method called on() that let's you, appropriately enough, do something "on" that event.

Let's say I want to alert "Hello" when a user clicks on the nodeObject

nodeObject.on('click', function(event){
   alert('hello');
});

Or let's say we want to add a border when a user first moves their mouse over an item:

nodeObject.on('mouseenter', function(event){
   this.setStyle('border', '5px solid #555');
});

Notice how the "this" object is used without wrapping it? It's automatically wrapped for you to be a Node object, which is incredibly convenient.

But what if, on the off chance, you *must* get the original DOM object. You can do nodeObject.getDOM() and it will return you the underlying DOM element.

This also applies to NodeList objects as well.

So if you do A.all('div').getDOM() it will return you an array of plain DOM elements.

What if about if you need to remove an event?

Let's say you do this:

nodeObject.on('click', myFunc);

you can detach the event by simply doing:

nodeObject.detach('click', myFunc);

or you could even just remove all events by not passing a second argument, like this:

nodeObject.detach('click');

What if you want to do some work on document ready?

You can do:

A.on('domready', function(event){
   // More work here
});

Now, there are times when you want to both load some modules and fire your callback on DOM ready, so here is how you would do that in Alloy:

AUI().ready('event', 'node', function(A){
   // This code will fire on DOM ready 
   // and when this modules are ready
});

Here's an interesting example. Let's say you want to listen on the node for only a specific key combination. For instance, you want to only fire the event when the user presses the escape key, but only when holding down the shift key.

Here's how you would listen to it:

nodeObject.on('key', function(event){
   // escape + shift has been pressed on this node
}, 'down:27+shift');

Now here's another use case some might be curious about. What if you want to prevent the default behavior of an event, for instance, if you want to stop a link's href from being followed?

nodeObject.on('click', function(event){
   event.preventDefault();
});

In Javascript, events bubble, which mean that by default, an even on one element also happens on every element that contain it, so if you click on a link, it will also fire an event on the body element as well.

You can stop your event from bubbling though, here's how:

nodeObject.on('click', function(event){
   event.stopPropagation();
});

You might notice that these are the same methods that exist in the W3C specification, but they're normalized to work the same in all browsers.

But there's also a shortcut if you want to just preventDefault and stopPropagation, which is like so:

nodeObject.on('click', function(event){
   event.halt();
});

Event delegation

Speaking of event bubbling, built into Alloy is event delegation. Event delegation is a technique that let's you can attach one event to a container but have it fire only on the children elements.

Imagine you have a list, and a lot of LI elements inside of it. You could add a new event listener for each element, but as your list grows, the number of listeners will also grow, as well as memory consumption.

And let's say you add elements via ajax, it's a pain to have to reattach events after every update as well.

So let's say go through an example. Let's say that we have this HTML:

<ul id="myList"><li>Test</li></ul>

Here's how we would use delegation:

var myList = A.one('#myList');
myList.delegate('click', function(event){
   alert(event.currentTarget.html());
}, 'li');

Notice a few things. One, we're calling a method called delegate, but it's very similar to "on". In fact, the only difference to the "on" method is that the third parameter is a selector that we will test to make sure the element matches before firing the function.

But also notice that we're referencing event.currentTarget. This is a property that will always point to the element that you are currently listening for, even inside of the "on" method, so I recommend using it.

But now that we've added our event, if you click on the list item, it will alert the contents of that item. Now let's try this:

myList.append('<li>Test 2</li>');

It will add another list item, and when you click on this new item, it will alert "Test 2", without having to reattach the event.

Conclusion

Hopefully this helps show you some of the helpful ways you can work with elements on your page, and help get you up to speed.

Showing 1 - 5 of 33 results.
Items: 5
Page: of 7