Darren Mothersele

London based Drupal Web Developer
Drupal.org Google+ Facebook Twitter GitHub LinkedIn RSS Feed

jQuery UI Widgets, Drag and Drop (London Drupal Drop In Dec 2011)

Another great Drupal London event last night!

Chris (matason on Drupal.org) gave a great presentation of the new Drupal 7 Workbench module. It was great to see it in action and one I can see using myself a lot in the future. John and Rob demonstrated their Survey Builder module, a new backend for the excellent Form Builder tool. This looks like it has a lot of potential, so one to keep an eye on for the future I think. Vamory gave a really useful guide to making multi-step forms in FAPI, and then I got to talk about one of my pet favourite subjects, jQuery!

I showed the Active Tags module, and demonstrated adding some of the jQuery UI widgets to a Drupal 7 site, then showed how to build up a more complex interaction by adding Drag and Drop functionality to a couple of Drupal Views, then hooking up a Rules backend linked together by Page Manager. In case you missed it, or wanted more details, read on...

You can get the full set of slides (minus the screen cast video demos) from my slideshare account by clicking the above title image.

Progressive enhancement is a method for adding nice interaction and widgets to your Drupal site while maintaining compatibility for non-javascript browsers, and accessibility. It basically means you generate the HTML for your widget then insert it into the HTML DOM object using Javascript. Then you hide the old widget. When a user interacts with your widget you have to complete the value in the old widget, so for example, if the old widget was a text box and you have replaced it with a slider, when the users moves the slider you have a Javascript function attached to the change event that takes the new position of the slider and puts it into the text box. This means that users without javascript just see the old widget, but most users get the better experience of using the jQuery widgets.

Active tags is a Drupal module that offers a replacement widget for the Drupal core tagging field. Instead of textbox requiring a comma separated list of tags, you insert the tags one at a time and press enter or click the add button. Behind the scenes this builds up the comma separated list in Drupal's own textfield, so it doesn't affect how Drupal sees the tags.

I talked for a bit about various ways of including Javascript code in your Drupal site, ways for themers to include it in Drupal Themes, and lots of ways for module developers to use drupal_add_js(). I pointed out that most widget and interface stuff might be better put in a module so it can persist if you change themes on the site.


I mentioned drupal_add_js(), hook_library() and drupal_add_library() as ways to include Javascript code, and gave some simple examples of attaching jQuery UI Widgets to Drupal Forms. I wont go through the examples here, if you want to you can get the slides and look. It was just some simple code examples:


Turn the login block into a dialog box


Change a set of radio buttons into jQuery UI buttons

There was also an example to make a textarea automatically resize to fit the content as you type, using the jQuery autoResize plugin.

I explained how Drupal Behaviors are used as a replacement for the $(document).ready() function in Drupal. There's more information about this in the Drupal documentation page Managing Javascript in Drupal 7.

Now we get to building a more complex user interaction using jQuery UI and Drupal. In this example I create two views. One where the items become Draggable, and another view that becomes the Droppable target. This fires off a drop event, which triggers an AJAX call back to Drupal. Page manager picks up this request and passes it on to Rules where it is processed. I posted a brief video demo of it in action at the top of this post.

This site has a content type called Meeting, and a Relation (called attendee) that links users to meetings. The interaction we are building creates a relation item when a user is dropped on the meeting.

The two views are created using Views in the usual way. I've chosen to make one a simple unformatted list, and one as a grid view, but the drag and drop interactions can be attached to any DOM element. In the first view (Staff members) I have overridden the output to put the .dproj-draggable class on each item. This is
what will be used to attach the draggable interaction. In the second view I have added the .dproj-droppable at the View level ('CSS classes' in advanced options in View) so the whole view can be given the jQuery UI droppable interaction.

When the draggable is dropped on the droppable an event is fired. This event is assigned a callback function that sends a request back to Drupal via AJAX. In order to do this is must have a callback path that includes arguments to indicate what was dropped where. This is why we build a callback from two parts, one from the dragged item and one from the dropped item. These two arguments are generated as part of the views, as a span wrapped in a callback class. This allows us to hide them from the user using CSS and extract their values in the jQuery drop event.

Here is the code that powers this:

The draggable is just given one option. The revert option is set to 'invalid' which means that if a draggable is dropped anywhere other than a valid droppable area it reverts back to it's original position.

The droppable takes a few more options. The most important being the 'drop' function that is called when a draggable is dropped on the droppable. You can access the droppable element using 'ui.droppable' as passed in to the drop function. In this function I am doing a few things:

I hide the original droppable (you might want to revert it if you want to allow it to be dropped again elsewhere), then fade out the droppable slightly to give some visual feedback that something is happening.

Then I work out the ID of the view that has been dropped on, this is because I will later need to extract this view from the response and replace the current version with the new version of the view from the AJAX response.

I then calculate the callback path using the hidden callback element from the dragged item and the droppable. Then make an AJAX call using $.ajax to this callback path. The ajax takes a success function that it calls when the ajax response comes back. This function parses the new version of the view from the data that is returned, replaces the version in the page with this new version, then fades the view back to full.

Page manager (part of ctools) is used to register the callback function with Drupal. This allows you to specify a path with arguments. As you can see above I have specified two arguments, the user and the node, i.e. the dragged item and the item it was dropped on.

Here the arguments are converted into a context, you can load up the related entities, making them available for Rules.

You need the Rules Bonus Pack for this. It provides a module called 'Miscellaneous' which includes a really cool bit of functionality for linking Page Manager to Rules. You can see this in the above image. It creates a reaction that triggers an event in Rules.

You can then use Rules to process the request. Set up a rule to trigger on the event you created in Page manager. Then add the following actions:

  • Create a new variable of type 'list of entities'
  • Add the user entity to the list
  • Add the meeting node entity to the list
  • Create a new Relation entity, using the list as it's value
  • Force a redirect to a page that just includes the updated view matching the droppable.

I hope that explains everything. If you have any questions, drop me a line or leave a comment and I'd be happy to try an explain further.

I thought this was a really interesting presentation. We've been using jquery_ui recently and have been impressed with how easy it is it use. Wasn't aware of the rules / page manager integration - neat!

Oh, and thanks for making an example of me :)

John

The drag and drop functionality you have shown looks great, and I think it opens up drupal to a world of exciting capabilities.

What is the chance of getting a step-by-step screencast posted? The outline above is helpful but is still slightly difficult to folllow in full for a new drupal user. Thanks

Thank you for showing us how jquery can be used within drupal. I too wasn't aware of the page manager integration. I also agree with the post above that a screencast could be very useful.

Pete

As soon as I've stopped celebrating the festival period I'll get a screencast recorded.

Thanks Darren, appreciate it. Hope you enjoy your break.

I'm looking forward to the screencast as well.

A screencast would be hugely helpful. Thanks.

Are we any closer to getting a screencast? I am really looking forward to this one. Thanks in advance

Yes, closer. I wrote a script for it, I just have to find a couple of hours to sit down and record it!

Darren, thanks so much for moving forward with the screencast. I'm eager to watch it and learn!

Post new comment
The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

Recent comments
Latest Posts