Skip to content

Step 7 ajaxed countdown

opensas edited this page Nov 3, 2011 · 10 revisions

Step 7 - ajaxed countdown

Purpose: in this step we will add a count down, showing the time remaining for the next event. We will also show how to use your own libraries and how to make them get along with play's dependencies system.

cd ~/devel/apps
git clone git://github.com/opensas/play-demo.git
cd play-demo
git checkout origin/07-ajaxed_countdown

Create a utility library

From eclipse, create a new DateHelper utility class in the package lib.utils. This class will provide a method to establish the elapsed time between to dates.

lib.utils.DateHelper

package lib.utils;

import java.util.Date;

import org.joda.time.Period;

public class DateHelper {

	public static String dateDiff(final Date begin, final Date end)  {
		
		final Period p = new Period(begin.getTime(), end.getTime());
	
		String message =
			    addTime(p.getYears(), "year") +
			    addTime(p.getMonths(), "month") +
			    addTime(p.getDays() + (p.getWeeks()*7), "day") +
			    addTime(p.getHours(), "hour") +
			    addTime(p.getMinutes(), "minute") +
			    addTime(p.getSeconds(), "second");
		
		message = message.replaceAll(", $", "");
		
		return message;
	}

	private static String addTime(final Integer time, final String period, final String periods) {
		if (time==0) return "";
		return String.valueOf(time) + " " + (time==1 ? period : periods) + ", ";
	}
	private static String addTime(final Integer time, final String period) {
		return addTime(time, period, period + "s");
	}
	
	// non instantiable class
	private DateHelper() {
		throw new AssertionError();
	}
}

Export it as a jar file and save it to lib directory, and then remove it from the project.

Now exit eclipse, go to the app folder and from the command the run

play eclipsify

Open eclipse and import once again the project, and now your utility class is available.

This method works fine, but it doesn't get along too wel with play's dependencies system, just try the following:

play deps
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.3, http://www.playframework.org
~
~ Resolving dependencies using /home/sas/Dropbox/Public/devel/play/apps/play-demo/conf/dependencies.yml,
~
~
~ Installing resolved dependencies,
~
~ 	modules/crud -> /home/sas/devel/opt/play-1.2.3/modules/crud
~
~ *****************************************************************************
~ WARNING: Your lib/ and modules/ directories and not synced with current dependencies (use --sync to automatically delete them)
~
~ 	Unknown: /home/sas/Dropbox/Public/devel/play/apps/play-demo/lib/DateHelper.jar
~ *****************************************************************************
~
~ Done!
~

So we'll tell play that we are using a local repository. For more info checkhere.

Create a folder named jar from the root of your application, and move the file DateHelper.jar there, adding a version number:

cd ~/devel/apps/play-demo
mkdir jar
mv lib/DateHelper jar/DateHelper-1.0.jar

Then edit the dependencies file

conf/dependencies.yml

# Application dependencies

require:
    - play -> crud
    - provided -> DateHelper 1.0 
repositories: 
    - provided: 
        type:       local 
        artifact:   "${application.path}/jar/[module]-[revision].jar" 
        contains: 
            - provided -> * 

and finally run play deps again

play deps
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.3, http://www.playframework.org
~
~ Resolving dependencies using /home/sas/Dropbox/Public/devel/play/apps/play-demo/conf/dependencies.yml,
~
~ 	provided->DateHelper 1.0 (from provided)
~
~ Installing resolved dependencies,
~
~ 	modules/crud -> /home/sas/devel/opt/play-1.2.3/modules/crud
~ 	lib/DateHelper-1.0.jar
~
~ Done!

Create a nextEvent action

Now we will create an action in Application controller that will fetch the next event from the database.

controllers.Application

    public static void nextEvent() {
    	Event nextEvent = Event.find("date > ? order by date", new Date()).first();
    	render(nextEvent);
    }

Will add a method to the Event model to tell us the time remaining for the event

models.Event

[...]
	public String countDown() {
		return DateHelper.dateDiff(new Date(), date);
	}
[...]

and we'll also create a template for this partial

views/Application/nextEvent.html

<p class="lead">
#{if nextEvent}
	<span class="event-countdown">Only ${nextEvent.countDown()} to</span><br />
	<span class="next-event">${nextEvent.name}</span><br />
#{/if}
#{else}
	<span class="no-events">No events in sight...</span><br />
#{/else}
</p>

You can test it navigating to http://localhost:9000/application/nextEvent. If there are no events in sight, change any event's time to a future date and try again.

Create a header to show the time remaining for next event

create the file

views/partials/header.html

	<div id="masthead">
		<div id="next-event"></div>
	</div>
	
<script type="text/javascript">
	$('#next-event').load('@{nextEvent()}');
	setInterval(function() {
		$('#next-event').load('@{nextEvent()}');
	}, 2000);
</script>

and include it in the main template

views/main.html

[...]
    <body>
        #{include 'partials/topbar.html' /}
        #{include 'partials/header.html' /}
        <div class="container">    
            #{doLayout /}
        </div> <!-- /container -->
        #{include 'partials/footer.html' /}
    </body>
[...]

You can see it in action at http://localhost:9000


Our site is almost ready, now we are going to Step 8 - pretify urls.