Managing Relations with JQuery sortable
Under Notes
For Drupal 7 there are several contributed modules like References and Entityreference, that allow you to relate entities. Though these are stable and mature modules, we’ve have been using the Relation module for a couple of projects with great success.
Relations are separate entities, fieldable out of the box and allow you to build pretty complex relations. While it provides several ways for the end user to create these relations, it is mainly an API module and the provided methods might not always fit the use case for a particular project. This blog post explains how we use JQuery Sortable to allow users to relate Questions to a Survey through an intuitive drag and drop interface.
##Basic setup To set up the sorting of questions we need a basic structure, in this case we’ll use two separate Views. One view will show a listing of all the questions already added to the survey (left side of the image) and the other will show all the available questions in our repository (right side). For jQuery sortable to work, it is important that the Format of both views is set to a List.
The jQuery Ui sortable plugin will handle the sorting but we need to add some classes to the views to make them visible to it. Each view will need its own unique class and a common class to relate them. In our project we use survey-questions
for the survey’s questions listing, available-questions
for the question repository and connect-sortable
as the common linking class.
When configuring the views, it’s also important to define a ‘No results behaviour’ to make sure that there is always a drop target, even when the view returns no result. In our example we add a Global text field with the following value <li class="empty">No questions were added to this survey yet.</li>
.
To be able to use the jQuery sortable library, we need to include it in our module. Since the library is already in the Drupal core, we just activate it by adding the following code to our page generator function:
##Adding and sorting With the basic structure set up, we can enable the sortable plugin on both lists. The snippet below show a basic instantiation on the plugin.
##Saving data That’s the basic setup in order to make the lists sortable. Now we need a way to save the changes that can occur in three flavors:
- A question is added to the survey list, i.e., the survey-questions list receives an item.
- A question is removed from the survey list, i.e., the available-questions list receives an item.
- The questions are re-ordered in the survey
Using the jQuery sortable event callback we can capture these changes and show a save button.
###New questions
After clicking on the save button, the node id of the survey and a serialized version of the questions (question[]=14&question[]=12&question[]=17
) is sent to a page for processing. Through the serialization we know that the question with id 14 is the first, id 12 is the second and so on, allowing us to easily set the order.
###Deal with existing relations
It is also possible, however, that a user makes changes to a survey with already existing questions. In this case, we add the relation ID in the serialization to ease the update process. It will look something like question[]=nid-rid
, where nid
is the node ID of the question and rid
the relation ID. The final look of the serialization will be something like: question[]=14-50&question[]=12-45&question[]=17
###Under the hood The first thing we do is find out which relations (of type survey_question) are to be added, which to be updated and which to be removed.
The relations to be updated are the ones with the relation id in the serialization, so those are easy to find out. The remaining questions in the serialization are the ones whose relation needs to be created.
The tricky part is to find out the relations to be deleted. To accomplish this we load all the existing relations for that survey and match them against the ones in the serialization. Those we don’t find in the serialization are deleted.
Now, using the functions provided by the relation module, relation_load(), relation_create(), relation_save(), relation_delete(), we can handle all the data present in our $relation array.
In this example we focused on Adding and Sorting the questions. More advanced features such as editing fields of the relations might be part of a future blog post. We leave you with the slides of a presentation made during the Drupal meetup at Liberdade 229, last February: https://speakerdeck.com/danielfdsilva/drupal-relations-with-drag-and-drop.