Medication Reminder

Development Status: Active – Beta

Click here for the Change Log.

Click here for a list of planned features / work remaining.

Click here to go to the web app.

Main Features: (implemented or pending)

  • Pure HTML5 / CSS3 / Javascript web application (compatible with computers and most smartphones)
  • HTML5 localstorage for offline usage
  • Medication repetition similar to Google Calendar event repetition
  • Auto-complete pre-populated with ~1500 prescribed medications
    • Generic and Brand Name
  • History of actual time medication was taken
  • Scheduled notification reminders to take medication – Planned (dependent on PhoneGap’s capabilities)

Development Notes:

This is my first project using Subversion for version control, and I’m glad to have it up and running. Now I can work on this project (and future projects) from anywhere. The change log will also be populated by the Subversion commit comments…hopefully.
 
This project started off as a proposition from my sister, which I agreed to; realizing it would not only give me more experience developing web applications but also another project to include on a resume and serve as an example of work.
 
I quickly implemented an idea of a simple one-touch method to let the app know you’ve taken a medication, found here. (Click the “Add Pill” button, give it any name and click “Add”, then click the check icon to see it record the timestamp)
 
From there I began researching HTML/Javascript based event calendars but was unable to find anything free that completely met my needs. I first tried FullCalendar (see attempt here), but that did not have built in support for repetitions. I glanced at an iCalendar implementation (since iCal is a standardized format with support for repetitions) but it was only for generating iCal events without any actual calendar rendering.
 
Then I settled on jQueryUI’s datepicker. I was able to change it to a fluid layout sized calendar and populate the days with information. Even though FullCalendar could already do this, I wasn’t able to quickly figure out how to implement repetitions using their format whereas with jQuery UI’s datepicker, there was no format so I could use whatever method I was using to keep track of the data.
 
With the calendar view decided, the last major hurdle was implementing repeating events. Not knowing what format to use, I decided to mimic Google’s Calendar repetition, which worked quite well. For storage, I’m simply keeping track of any event IDs associated with a particular date.
 
Just about all that’s left is touching up the user interface (adding success / warning / error CSS classes and fixing errors in the expected logical flow of the user interface) and then I’m ready to convert it to a PhoneGap app to try implementing scheduled notifications.

How to make a collapsible split list in jQuery Mobile

Introduction:

Screen real estate is valuable, especially on a mobile device. If you have a lot of information you want to display that can be grouped under a common header / theme, a great solution is to use a collapsible listview found in the jQuery Mobile library.
 
However, what do you do when you want to combine the functionality of a collapsible list with that of something that has a common button among the list items that would allow you to edit / delete / perform some action on the list item that is common to all the items on the list (like a jQuery Mobile Split List)?
 
The following tutorial will walk you through on how to create a collapsible split list in jQuery Mobile and will utilize some custom CSS and JavaScript to get the job done.

Tutorial

Lets start off with a basic split list, taken and modified from the jQuery Mobile Listview tutorial (converted listview to split list, changes highlighted):

<ul data-role="listview" data-inset="true" data-split-icon="delete">
	<li>
		<a href="#">
			<h2>Stephen Weber</h2>
			<p><strong>You've been invited to a meeting at Filament Group in Boston, MA</strong></p>
			<p>Hey Stephen, if you're available at 10am tomorrow, we've got a meeting with the jQuery team.</p>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#">
			<h2>jQuery Team</h2>
			<p><strong>Boston Conference Planning</strong></p>
			<p>In preparation for the upcoming conference in Boston, we need to start gathering a list of sponsors and speakers.</p>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#">
			<h2>Avery Walker</h2>
			<p><strong>Re: Dinner Tonight</strong></p>
			<p>Sure, let's plan on meeting at Highland Kitchen at 8:00 tonight. Can't wait!</p>
		</a>
		<a href="#">Delete</a>
	</li>
</ul>

Using the code above, you should get something similar to the following:
(note the following is using jQuery Mobile 1.4.2 and jQuery 1.9.1, yours may look different if you’re using a different theme / version of jQuery Mobile / jQuery)
 

 
In this contrived example, that’s a decent amount of potentially useful information. However, on a mobile device, the amount that is displayed at one time is limited and if the user was looking for something at the bottom, they would have to scroll through the content of everything else. Lets add another div to enclose the content we want to hide:
(changes highlighted)

<ul data-role="listview" data-inset="true" data-split-icon="delete">
	<li>
		<a href="#">
			<h2>Stephen Weber</h2>
			<div style="display:none;">
				<p><strong>You've been invited to a meeting at Filament Group in Boston, MA</strong></p>
				<p>Hey Stephen, if you're available at 10am tomorrow, we've got a meeting with the jQuery team.</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#">
			<h2>jQuery Team</h2>
			<div style="display:none;">
				<p><strong>Boston Conference Planning</strong></p>
				<p>In preparation for the upcoming conference in Boston, we need to start gathering a list of sponsors and speakers.</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#">
			<h2>Avery Walker</h2>
			<div style="display:none;">
				<p><strong>Re: Dinner Tonight</strong></p>
				<p>Sure, let's plan on meeting at Highland Kitchen at 8:00 tonight. Can't wait!</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
</ul>

Resulting in:
 

 
The bulk of the content is gone, and the height changed from 307 px to 174 px, a difference of 133 px or ~44 px per list item. That’s a lot of recovered space…but how do we get the content back?
 
For that, we’ll need to write some custom javascript. What we need to do is target the link that was clicked, and un-hide the div that we had hidden. Luckily, this is very easy:

$(document).on("click","ul a", function(){
	$(this).children("div:last").toggle(200);
	if($(this).attr("title")) {
		console.log("clicked delete");
	} else {
		//Clicked the link to toggle the content
	}
});

Brief explanation:

$(document).on("click","ul a", function(){

This defines a function to be called whenever a link is clicked within an unordered list.

$(this).children("div:last").toggle(200);

$(this) refers to the link we’ve selected, .children(“div:last”) targets the last div element that is nested within the link (more on this in a minute), and .toggle(200) tells jQuery to hide/unhide the div, animating it over 200 ms.

if($(this).attr("title")) {

The text we put inside the link for the delete icon is used to populate the title attribute (in this case “Delete”). Since no title was supplied for the collapsible content, the title attribute will not be set, and the code within this if-statement will only be executed when the delete icon is clicked. If you provided a title attribute for the collapsible content, you could easy filter it out by doing a comparison in the if-statement.


When combined with the code above, we should get something that looks like this:
 

 
When you click on each of the list items, it’ll expand and collapse, displaying and hiding the content. Also, if you’re using Chrome, you can look in the browser console and change from “<top frame>” to “collapsible-split-list-3.html” and you’ll see “clicked delete” appear whenever you click the delete icon. Other browsers that allow the viewing of the console should also show “clicked delete”, but the method to find that is outside the scope of this tutorial.
 
Now, in the above javascript code, why did I specifically target the LAST div when there’s only 1 div to begin with? Because currently, there isn’t any indication that the list items can be clicked to display more information, and since jQuery Mobile doesn’t natively support collapsible split lists / multiple icons for lists, we need to add another div to put the icon in there:
The HTML (changes highlighted)

<ul data-role="listview" data-inset="true" data-split-icon="delete">
	<li>
		<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
			<h2>Stephen Weber</h2>
			<div style="display:none;">
				<p><strong>You've been invited to a meeting at Filament Group in Boston, MA</strong></p>
				<p>Hey Stephen, if you're available at 10am tomorrow, we've got a meeting with the jQuery team.</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
			<h2>jQuery Team</h2>
			<div style="display:none;">
				<p><strong>Boston Conference Planning</strong></p>
				<p>In preparation for the upcoming conference in Boston, we need to start gathering a list of sponsors and speakers.</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
	<li>
		<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
			<h2>Avery Walker</h2>
			<div style="display:none;">
				<p><strong>Re: Dinner Tonight</strong></p>
				<p>Sure, let's plan on meeting at Highland Kitchen at 8:00 tonight. Can't wait!</p>
			</div>
		</a>
		<a href="#">Delete</a>
	</li>
</ul>

The CSS for the “iconFloat” class:

.iconFloat {
	float: left;
	margin-top: 0px;
	margin-bottom: 0px;
	border-top-width: 0px;
	border-bottom-width: 0px;
	border-left-width: 0px;
	border-right-width: 0px;
	top: 2px; //this will vary depending on application
	padding-bottom: 0px;
}

Now we have a collapsible split list with a plus icon to indicate that there’s more content and a delete icon, but when you click on the list item, it expands but doesn’t turn into a minus icon like would logically be expected. To fix that, we need to add one more line to our javascript code above:
The Javascript (changes highlighted):

$(document).on("click","ul a", function(){
    $(this).children("div:last").toggle(200);
    if($(this).attr("title")) {
        console.log("clicked delete");
    } else {
        //Clicked the link to toggle the content
    }
	$(this).children("div:first").toggleClass("ui-icon-plus ui-icon-minus");
});

That is why we wanted to toggle the LAST div: because there would be 1 more div before it that would contain the collapsible icon (the FIRST div). The .toggleClass() function just adds / removes the specified classes (if the class is there, it removes it; if it isn’t, it adds it).
 
Combine it all together and you should have something like this:

Full HTML/CSS/Javascript

The full HTML/CSS/Javascript source used in the example above:

<html>
	<head>
		<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css" />
		<style>
			.iconFloat {
				float: left;
				margin-top: 0px;
				margin-bottom: 0px;
				border-top-width: 0px;
				border-bottom-width: 0px;
				border-left-width: 0px;
				border-right-width: 0px;
				top: 2px;
				padding-bottom: 0px;
			}
		</style>
	</head>
	<body>
		<div data-role="page">
			<div role="main">
				<ul data-role="listview" data-inset="true" data-split-icon="delete">
					<li>
						<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
							<h2>Stephen Weber</h2>
							<div style="display:none;">
								<p><strong>You've been invited to a meeting at Filament Group in Boston, MA</strong></p>
								<p>Hey Stephen, if you're available at 10am tomorrow, we've got a meeting with the jQuery team.</p>
							</div>
						</a>
						<a href="#">Delete</a>
					</li>
					<li>
						<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
							<h2>jQuery Team</h2>
							<div style="display:none;">
								<p><strong>Boston Conference Planning</strong></p>
								<p>In preparation for the upcoming conference in Boston, we need to start gathering a list of sponsors and speakers.</p>
							</div>
						</a>
						<a href="#">Delete</a>
					</li>
					<li>
						<a href="#"><div class="iconFloat ui-btn ui-corner-all ui-icon-plus ui-btn-icon-notext"></div>
							<h2>Avery Walker</h2>
							<div style="display:none;">
								<p><strong>Re: Dinner Tonight</strong></p>
								<p>Sure, let's plan on meeting at Highland Kitchen at 8:00 tonight. Can't wait!</p>
							</div>
						</a>
						<a href="#">Delete</a>
					</li>
				</ul>
			</div>
		</div>
		
		<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
		<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>
		<script lang="text/javascript">
		$(document).on("click","ul a", function(){
			$(this).children("div:last").toggle(200);
			if($(this).attr("title")) {
				console.log("clicked delete");
			} else {
				//Clicked the link to toggle the content
			}
			$(this).children("div:first").toggleClass("ui-icon-plus ui-icon-minus");
		});
		</script>
	</body>
</html>

Conclusion

By including 2 extra div’s per list item, a little custom CSS, and some minor event handling Javascript, we can effectively create a functional collapsible split list. From here, you can easily add function calls to the part of the code for when the user clicks the delete button or choose to do an additional task when the user expands/collapses the content.
 
 
Let me know if you found this tutorial helpful and if you’re using collapsible split lists in the comments below.