Wednesday, October 17, 2012

Liferay: dynamic data list detail

I've been working with Liferay 6.1's dynamic data lists for the last few days. I like how easy it is to create a CRUD system for data lists. The out-of-the-box functionality to display lists using the Liferay defaults and a custom VM-template is amazing.

To display a detail of a record, however, is a lot more painful. For some reason, there's no VM-template support there. So what I wanted to do, was the following:
  • Create a detail link in the list VM-template
  • Let the detail page display my own custom page
Not all that much asked, I'd think, yet this was NOT easy to achieve in Liferay. The documentation in this area is very limited, and basically only covers the creation of a list-template. So, first things first, I created my custom list-template using the Liferay documentation, and my dynamic data list looked good.

Of course, I wanted links in that list, to click through to the details of a record. This was the first difficulty I encountered. I couldn't find any clues or documentation on how to get the correct link. So what I did, was switching the list view back to 'default', and copied the link URL there. It looked really, really ugly.

I then started to dissect that URL. I concluded that there's lot of parameters I didn't need, so I stripped it down to the bare minimum: the portlet ID, a struts action and a record ID. The portlet ID and struts action can be copied from the URL the default list provides, the record ID is dynamic and can be fetched using $record.getRecordId(). My URL looked like this:

/your_page?p_p_id=169_INSTANCE_ToH96dipcgdr&struts_action=%2Fdynamic_data_list_display%2Fview_record&recordId=$record.getRecordId()
This of course redirects to the default detail page, which might be OK for adding and editing records, but not for displaying them in an enterprise application. I somehow had to either edit the detail page, or find a way to redirect the detail-link to another page.

That was the second obstacle. Editing the detail-page wasn't really an option, since it would then be altered for ALL detail pages of all records, not just the ones I wanted to display at that time. With that idea out of the way, I had to find a way to make the detail URL redirect to a custom JSP. Therefor, I had to create a new struts action, and map it to a new JSP I also had to create.

The easiest way to do that is using a hook. In that hook, we need to do 3 things:

  • Create an Action class (extending from BaseStrutsPortletAction)
  • Create a custom JSP
  • Map the Action class to a certain path
The last one is the easiest: simply add this to your liferay-hook.xml

  /dynamic_data_list_display/view_office
  be.c4j.hook.action.SomeAction
 
This means you have to change the struts-action parameter in your detail-url to %2Fdynamic_data_list_display%2Fview_office. Of course, we also need to define the SomeAction class.

import com.liferay.portal.kernel.struts.BaseStrutsPortletAction;
import com.liferay.portal.kernel.util.ParamUtil;

import javax.portlet.PortletConfig;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import com.liferay.portlet.dynamicdatalists.model.DDLRecord;
import com.liferay.portlet.dynamicdatalists.service.DDLRecordLocalServiceUtil;

public class SomeAction extends BaseStrutsPortletAction {

 @Override
 public String render(PortletConfig portletConfig, RenderRequest renderRequest,
   RenderResponse renderResponse) throws Exception {
  
  long recordId = ParamUtil.getLong(renderRequest, "recordId");
  
  DDLRecord record = DDLRecordLocalServiceUtil.getRecord(recordId);
  
  renderRequest.setAttribute("ddlRecord", record);
  
  return "/portlet/dynamic_data_lists/view_office.jsp";
 }
}

Now all you have to do is build the JSP. Make sure you place in the folder $customs_jsps$\html\portlet\dynamic_data_lists. In the JSP you can access the ddlRecord attribute.

<%
DDLRecord record = (DDLRecord)request.getAttribute("ddlRecord");

%>; 

This is a field of our record<%= record.getFieldValue("fieldName") %>;

If you know what to do, it isn't all that hard, but it took me a lot of time to figure this out. Liferay offers a lot of out-of-the-box functionality, but sometimes you have to go through a lot of trouble for adding just that little extra.