Tips & Tricks: add new structure’s field into web content

During my everyday work some people asked me: „Is it possible to add new type of structure’s field. If yes, how can I do it?”. In my opinion the fastest way to achieve this result is overriding few files in ext plugin or hook. We decided to use hook. In this post We show you the example, how we did it. Our new field is a datetime component.

Firstly, we should know in liferay there are two places where we can add and edit structure’s fields, So we must check our new functionality two times:

  1. CP -> Web content -> Structures (tab) -> Add or edit structure
  2. CP -> Web content -> add or edit web content -> change structure

Files which are responsible to render and serve structure’s fields in first point:

  • html/portlet/journal/js/main.js
  • html/portlet/journal/edit_article_content_xsd_el.jsp
  • html/portlet/journal/edit_structure_xsd_el.jsp

In second point:

  • html/portlet/journal/edit_article_structure extra.jspf
  • html/portlet/journal/edit_article_extra.jsp

Ok, let’s get started.

1. Create a new hook and configure that it can override jsps files. For example:

<hook>
<custom-jsp-dir>/custom_jsps</custom-jsp-dir>
</hook>

2. Copy html/portlet/journal/js/main.js into custom_jsps folder. In this step we must register new model’s field (below registerFieldModel method’s declaration).

registerFieldModel('Date', 'date', 'DateField', true);

Next we add new field’s type to map called „model” in function _fieldInstanceFactory()

var model = {
  'boolean': Journal.FieldModel.Boolean,
  'document_library': Journal.FieldModel.DocumentLibrary,
  'image': Journal.FieldModel.Image,
  'image_gallery': Journal.FieldModel.ImageGallery,
  'link_to_layout': Journal.FieldModel.LinkToPage,
  'list': Journal.FieldModel.List,
  'multi-list': Journal.FieldModel.MultiList,
  'selection_break': Journal.FieldModel.SelectionBreak,
  'text': Journal.FieldModel.Text,
  'text_area': Journal.FieldModel.TextArea,
  'text_box': Journal.FieldModel.TextBox,
  'date': Journal.FieldModel.Date
};

3. Copy html/portlet/journal/edit_article_content_xsd_el.jsp and add code inside journal-article-component-container. We compare our new type with elType variable.

<c:if test='<%= elType.equals("date") %>'>
  <%@ include file="/html/portlet/journal/edit_article_content_xsd_date_el.jspf" %>
</c:if>

Ok, it  looks fine, but what’s is in edit_article_content_xsd_date_el.jspf“? This is the main point of this tutorial. In this file we define „look and feel” our new component. For example:

<aui:fieldset>
<%
Calendar cal = CalendarFactoryUtil.getCalendar(timeZone, locale);
if (elContent != null && !elContent.equals("")) {
  DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd H:m");
  Date date = (Date)formatter.parse(elContent);
  cal.setTime(date);
}

%>

<aui:field-wrapper>
  <div>
    <liferay-ui:input-date
      dayParam="dateDay"
      dayValue="<%= cal.get(Calendar.DATE) %>"
      disabled="<%= false %>"
      firstDayOfWeek="<%= cal.getFirstDayOfWeek() - 1 %>"
      monthParam="dateMonth"
      monthValue="<%= cal.get(Calendar.MONTH) %>"
      yearParam="dateYear"
      yearValue="<%= cal.get(Calendar.YEAR) %>"
      yearRangeStart="<%= cal.get(Calendar.YEAR) %>"
      yearRangeEnd="<%= cal.get(Calendar.YEAR) + 5 %>"
    />

    &nbsp;

    <liferay-ui:input-time
      amPmParam="dateAmPm"
      amPmValue="<%= cal.get(Calendar.AM_PM) %>"
      hourParam="dateHour"
      hourValue="<%= cal.get(Calendar.HOUR) %>"
      minuteParam="dateMinute"
      minuteValue="<%= cal.get(Calendar.MINUTE) %>"
      minuteInterval="<%= 1 %>"
    />
  </div>
</aui:field-wrapper>
</aui:fieldset>

You must know that elContent variable contains our field’s value (date in this example).

4. Copy html/portlet/journal/edit_structure_xsd_el.jsp and add our new type into select’s list.

<option <%= elType.equals("date") ? "selected" : "" %> value="date"><liferay-ui:message key="date" /></option>

Okey, let’s deploy our hook and look into add structure form. What are we seeing? Oh, our new field’s type.
What’s next? We must allow to edit structure directly in edit article form.

5. Let’s look inside edit_article_structure_extra.jspf file and copy them. Then we define „look and feel” our new field inside journalFieldModelContainer div by adding new div with dataType=”<type>” attribute.

<div dataType="date">
<%
String elContent = "";
%>
<%@ include file="/html/portlet/journal/edit_article_content_xsd_date_el.jspf" %>
</div>

6. In file html/portlet/journal/edit_article_extra.jsp we add to menu (lists of field’s types) our new component because we want allow „drag and drop” functionality. So we create new div’s tag with dataType=”<type>” attribute inside journalComponentList div.

<div dataType="date">
<liferay-ui:message key="date" />
</div>

We have new component with great design but how we save selected date and time value. Let’s see main.js file. There is getContent method where there are a lot of “if” conditions. So, we must write a new one:

if (type == 'date') {
	var dateContents = componentContainer.all('select');
	var date = [Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN];

	if (dateContents) {
		dateContents.each(
			function(select, selectIndex, selects) {
				var options = select.all('option');
				if (options) {
					options.each(
						function(option, optionIndex, options) {
							if (option.get('selected')) {
								//name selecta, zawierajacego wybrany item
								var selectName = select.get('name');
								var selectedValue = option.val();

								if (selectName.match(/dateDay$/)) {
									date[0] = selectedValue;
								} else if (selectName.match(/dateMonth$/)) {
									date[1] = selectedValue;
								} else if (selectName.match(/dateYear$/)) {
									date[2] = selectedValue;
								} else if (selectName.match(/dateHour$/)) {
									date[3] = selectedValue;
								} else if (selectName.match(/dateMinute$/)) {
									date[4] = selectedValue;
								} else if (selectName.match(/dateAmPm$/)) {
									date[6] = selectedValue;
								}
							}
						},
						select
					);
				}
			}
		);

	}
	content = instance.getDateAsString(date);

}

Also we must define the „getDateAsString” function

getDateAsString: function(stringDateArray) {
		if (stringDateArray.length != 7) {
			return '';
		}
		var intDateArray = new Array(stringDateArray.length);
		var notNaNExist = false;
		for (var i = 0; i < stringDateArray.length; i++) {
			intDateArray[i] = parseInt(stringDateArray[i], 10);
			if (intDateArray[i] != NaN) {
				notNaNExist = true;
			}
		}

		if (!notNaNExist) {
			return '';
		}

		var day = intDateArray[0];
		var month = intDateArray[1];
		var year = intDateArray[2];
		var hour = intDateArray[3];
		var minute = intDateArray[4];
		var second = 0;
		var ampm = intDateArray[6];

		if (!isNaN(month)) {
			month = month + 1;
		}

		if (ampm == 1 && !isNaN(hour)) {
			hour = hour + 12;
		}

		if (month < 10) {
			month = '0' + month;
		}
		if (day < 10) {
			day = '0' + day;
		}
		if (hour < 10) {
			hour = '0' + hour;
		}
		if (minute < 10) {
			minute = '0' + minute;
		}
		if (second < 10) {
			second = '0' + second;
		}

		return year + '-' + month + '-' + day + ' ' + hour + ':' + minute;
	}

I know that my code is not optimal. This post is only tutorial how to write new fields of structure. If you have better idea how resolve this problem just write to me.

If you want download all source files or download ready to deploy war file click links:

* I wrote this hook using trunk version of liferay CE (rev. 70450)

Advertisements

41 Responses to Tips & Tricks: add new structure’s field into web content

  1. Julien says:

    Thank you

  2. Why, Liferay, Why??? says:

    AAAARRRGGGHHHHH!!!!! Why does anyone use Liferay????? If you want to do ANYTHING other than the standard deploy it’s 500 steps and completely counter-intuitive. I am not even going to pretend to follow this article.

    How it should work: CP->Custom Fields->Web Content
    Add new custom field of type date named Event Date
    CP->Web Content add new web content
    Oh look, there’s my Event Date.

    What? You want it to be more complicated than that? Okay how about
    Add that Event Date custom field, then add a new Structure and Template using the Event Date.

    Oh, no that’s not possible! Why? because in LIferay you can add custom fields BUT CAN’T USE THEM!

    Freak out. I’m just going to use Grails.

    • hienamx says:

      Oh my little apprentice, this is not simple Grails framework. It’s a CMS. You are complaining about adding CF, adding Structure and Template? Well the template step you can skip if you prepare for yourself Universal Template (it’s easy as a pie when you know Velocity). You want to skip Structure step to? But what if it will be used in a background and you don’t won’t to show it to you’re users? 🙂

      So if you know how you can use Custom Fields 😀

  3. Pingback: JIRA: SDB

  4. Jack Daniels says:

    Thanks for this tutorial. Have you tried contributing this solution to Liferay perhaps for inclusion in the base code?

  5. skulled says:

    Thank you very much! I’ll try it now 🙂

  6. Hi Piotr, I appreciated much your tutorial. By the way, I created my own hook following your instructions and using the liferay plugin sdk. The result that I get is that I can add the “date” type to my structures, but when i publish a new content in which structure the type “date” is defined, reopening the content I don’t get the value set for the field date. The same situations occur when I deploy the hook provided by you at the end of your tutorial.
    In addiction to this, I would like to create other types based on multiple instances of the ckeditor text_area type already defined in liferay, but I’m not able to load the same structure I created with 2 or 3 text areas (displaying different toolbar versions). Have you got any suggestion for me? Thanks in advance,
    Giuseppe.

  7. Manuel Moreno says:

    also failing

  8. Manuel Moreno says:

    This code doesn’t work:
    If you see
    edit_article_structure_extra.jspf

    and then substitute the include with the file -> edit_article_content_xsd_date_el.jspf

    elContent is always empty, so the date is always the system date

  9. Manuel Moreno says:

    Hi Piotr, I’m not able to put this to work, any help would be appreciated. I posted the problem just on the comment above.

    Any help would be really appreciated.
    Best Regards,
    Manuel.

  10. Manuel Moreno says:

    Ok, I have it working, with some changes.
    in edit_article_extra.jsp don’t forget to put class=”journal-component” … without it the drag&drop didn’t work.

    I also had the same problems reported by Giusseppe. I fixed it by removing all changes in the file edit_article_structure_extra.jspf

    I applyed it to 6.0.5

  11. Hi Manuel, thank you for the reply. Are you sure that your chages get the hook properly working? I made these changes, but unfortunately it doesn’t work (using Liferay CE 6.0.6). By the way, your first suggestion (edit_article_extra.jsp) seems already applied in the first release by Piotr: his hook is already ok with the “journal-component” and the drag&drop feature. At this time, my problem still remains unresolved 😦

  12. A says:

    Hi Piotr ,

    Thanks for the hook. can u plz help me to fetch the date in template?

    I am not getting the date in template.

  13. A says:

    Hi All,

    Sorry i am able to fetch the date , but when i publish a new content in which structure the type “date” is defined, reopening the content I don’t get the value set for the field date.

    Is anyone solved the above problem?

    • Piotr Filipowicz says:

      I was very busy, but now I have a little time, so today or tomorrow I’ll publish solution for your problem.

  14. Piotr Filipowicz says:

    Guys, I checked this tutorial. My code works on liferay in revision 70450. I found a few changes in main.js between 70450 and newer revision. My advice is to go step by step and copy-paste my code from tutorial to your files in your revision. If you have any problems with this steps just contact with me.

  15. Wtjzqohv says:

    Could you please repeat that? Lil Nymphet Pics 65807

  16. Andrius says:

    I had the following problems with this code:
    1) every time I save the article, the value of the date field decreases by 2 hours. This is caused by the fact that the value is saved in the database without TZ, but it is interpreted using the current users TZ. I fixed it by changing
    Calendar cal = CalendarFactoryUtil.getCalendar(timeZone, locale);
    into
    Calendar cal = CalendarFactoryUtil.getCalendar();
    in edit_article_content_xsd_el.jsp
    2) when editing the structure in content editor (extra), after editing field name (edit options) and saving it, the fields type will reset to ‘text field’. I fixed it by adding the line

    in select tag in the form fm3 in edit_article_structure_extra.jspf
    3) the calendar (which pops up on datepicker button click) selection does not change values of year, month or day selection fields. I did not find any solution to this yet. I am using Liferay 6.1b4. I would be gratefull for any thoughts on how to solve it.

    • Andrius says:

      4) even if I enter 24-based hours, it populated the hour field with 12-based values. I solved it by changing
      hourValue=””
      to
      hourValue=””
      in
      edit_article_content_xsd_el.jsp

  17. Samir says:

    Hello,
    I really apreciated this tutorial, thank you for the effort.
    I wonder how can I sort on such date in an asset publisher?
    Thank you.

  18. Snyltkej says:

    Will I be paid weekly or monthly? http://atieqeutiqy.de.tl cp bbs movies nude Does anyone else want to step on her neck to get her to shut the hell up? Hot as hell scene, but damn! that girl would be annoying as hell. You’d have to wear your Ipod.

  19. Nopynvcw says:

    Nice to meet you http://ybyqategyb.de.tl preteen panties bbs Damn ! I’ve been looking for this vid for so fucking long ! I only managed to get the last minute a few years ago. I never thought I’d find the whole scene. Thanks a lot 😉

  20. click here says:

    After I open up your Rss feed it appears to be a ton of garbage, is the problem on my side?

  21. Pingback: RE: Date type in Structure - Forums - Liferay.com

  22. PIOTR FILIPOWICZ,

    Thanks for your post. I got it working by the following your instructions. I was not even using code snippets from comments.
    The only exception is JS file. I guess I made some mistake. I was getting error during deploying in my Tomcat console. So I downloaded your .zip code and I copued your JS file. It compiled well.

    After following instructions you also need to create your custmo new structure and structure template. It is only one line of code in my struture template.

    $date.getData()

    So that was hook for Journal portlet. It’ll be cool to add some modification to Asset Publisher portlet to show our custom date in a list view of all articles (list of all web content).

    I noticed that you can set up onlu 2012 year or up. So this need modifications to add old date to some posts.

  23. I double checked everything, I got 2 things:

    1. to get it work do not perform step 6 at all
    2. if you click edit your web-content the custom date filed will be reset

  24. I just like the helpful information you provide for your articles. I’ll bookmark your blog and take a look at once more here regularly. I’m quite certain I’ll learn many new stuff proper right here! Good luck for the next!

  25. R says:

    Thank you so much.. Its an awesome article. Step by Step. and it worked for me as i needed date validation. Now i will implement email validation in this way. hope that too works in similar fashion.

  26. Surokeen says:

    Hi,

    Very usefull post!, because I’m pulling my heir out to get custom data flexible my first project in LifeRay. Actually I tried the hook from the zip posted but I have the following problems:

    – Doesn’t save the dates when saving the web content

    – I made this field repetible, when I add a new “instance” of the field when editing the web content this action modifies the structure, is that the liferay way? So when I try to save the web content liferay tells me to save the structure too (??)

    – When I click on the “trash” icon of the first item of this field it removes almost the whole web content.

    Can anyone help me about this?

    Thanks!!

    • Javi GC says:

      Hi Surokeen, the zip posted does not apply to the last portal version (6.1.1), it is for 6.0.5. You should overwrite each file as mentioned above. In my experience it went everything well unless that you repeat the field in the same article. I have one diff between what Piotr make, in the file “edit_article_structure_extra.jspf” instead of:
      _____________________________________________________________________

      _____________________________________________________________________

      i solve it by doing:
      _____________________________________________________________________

      _____________________________________________________________________

      Hope it helps

      • Javi GC says:

        It seems that the text does not appears properly:

        in the file “edit_article_structure_extra.jspf” instead of:

        i solve it by doing:

        I only removed the include of edit_article_content_xsd_date_el.jspf

  27. U created a number of outstanding tips inside ur posting,
    “Tips & Tricks: add new structures field into web content
    eo Networks about Liferay”. I may wind up coming to your blog soon enough.
    Thanks a lot ,Corina

  28. Hail! You just save my life!!! Thanks!!! 🙂

  29. prakash says:

    Excellent article …works perfectly….

  30. simage says:

    Regarding the problem:

    “Doesn’t save the dates when saving the web content”

    I had the same problem and it was solved by naming the datatype without whitespaces (when adding the new datatype to a structure, ie., in the Add Structure > XML Schema Definition > Add Row > ).

    Also, the point 5. of the tutorial is not needed (adding the includes to edit_article_structure_extra.jspf)

  31. Revan says:

    I want to drag individual field names, like First Name , Last Name, Email Address…..
    With this ‘registerFieldModel’ when I drag and drop a component same name is displaying for all the components. My requirement is what ever the field I drop, it should display the label name of that particular component.
    Suggest something on this.

  32. mARK says:

    Love this article, very well explained, and makes perfect sense. I stumbled upon this whilst looking for some direction in displaying Custom structure fields in an Asset Publisher’s ADT. IF anyone can point me in the right direction I will be most appreciative.

    mARK

  33. Thirumala says:

    Please could you help me How to Populate 2nd drop down based on first drop down in Web Content Structure.

    I have two Dropdown fields. 1)Country 2)State

    I am selected one value of Country Dropdown, based on country display dynamic values in 2nd dropdown State.

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: