jQuery Mobile - adding Local Storage

This post is more than 2 years old.

So about a week or so ago I had an idea about a simple jQuery Mobile application that would make use of Local Storage. That was a week ago. Turns out - the "simple" application turned out to be a royal pain in the rear. Not because of Local Storage, but because of some misconceptions and lack of knowledge on my part in jQuery Mobile. What followed was a couple painful days (and more than a few curse words) but after all of that, I feel like I've got a better understanding of jQuery Mobile and got to play with some new features. So with that being said, let's get to the app.

My idea was a rather simple one. Given a collection of art, allow the user to browse categories and view individual pieces of art. I've done this before as a jQuery Mobile example. But what I thought would be interesting is to add a simple "Favorites" system. As you browse through the art you can select a piece you like, add it to your favorites, and then later have a quicker way to access them. To make things even more interesting, I thought I'd make use of Local Storage. Local Storage is an HTML5 feature, and unfortunately, it isn't quite as sexy as Canvas so it doesn't get as many cool demos. But it's one of those - you know - useful things that is actually pretty well supported. Local Storage is basically a key system of data. You can store, on the browse, a key and a value. Like name="Raymond". Unlike cookies, this data is not sent to the server on every request. Rather, it just sits there on the client ready to be used by JavaScript. You've got access to both a permanent (localStorage) and session based (sessionStorage) API. The excellent DiveIntoHTML5 talks about Local Storage here. I won't talk any more about the API as it's rather quite simple and the Dive site explains it more than well enough. Before getting into this version though, let's quickly look at the initial, simpler version.

My application consists of three HTML files, all powered by ColdFusion. The home page will list categories, the category page will list art, and the detail page will show just an art piece. Let's start with the index page.


<cfset categories = application.artservice.getMediaTypes()>

<!DOCTYPE html> 
<html> 
	<head> 
	<title>Art Browser</title> 
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
	<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
	<script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
</head> 
<body> 

<div data-role="page">

	<div data-role="header">
		<h1>Art Browser</h1>
	</div>

	<div data-role="content">	
		<ul data-role="listview" data-inset="true">
			<cfoutput query="categories">
				<li><a href="category.cfm?id=#mediaid#&media=#urlEncodedFormat(mediatype)#">#mediatype#</a> <span class="ui-li-count">#total#</span></li>
			</cfoutput>
        </ul>        
	</div>

</div>

</body>
</html>

Note that I begin by asking for media types. Our database categories art by a media type and I'll be considering that my categories. The getMediaTypes method returns a query which means I can simply loop over it in my content.

Next up we have the category page - which is really just a slightly different version of the last one. Note though the use of the Home icon.


<cfparam name="url.media" default="">
<cfparam name="url.id" default="">
<cfset art = application.artservice.getArt(mediatype=url.id)>

<!DOCTYPE html> 
<html> 
	<head> 
	<cfoutput><title>Art Category - #url.media#</title></cfoutput>
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
	<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
	<script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
</head> 
<body> 

<div data-role="page">

	<cfoutput>
	<div data-role="header">
		<a href="index.cfm" data-icon="home" data-iconpos="notext">Home</a>
		<h1>#url.media#</h1>
	</div>
	</cfoutput>

	<div data-role="content">	
		<cfif art.recordCount>
			<ul data-role="listview" data-inset="true">
				<cfoutput query="art">
					<li><a href="art.cfm?id=#artid#">#artname#</a></li>
				</cfoutput>
	        </ul>        
		<cfelse>
			Sorry, no art in this category.
		</cfif>
	</div>


</div>

</body>
</html>

And finally, let's look at our detail page.


<cfparam name="url.id">
<cfset art = application.artservice.getArtPiece(url.id)>

<!DOCTYPE html> 
<html> 
	<head> 
	<cfoutput><title>Art - #art.name#</title></cfoutput>
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
	<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
	<script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
</head> 
<body> 

<div data-role="page">

	<cfoutput>
	<div data-role="header">
		<a href="index.cfm" data-icon="home" data-iconpos="notext">Home</a>
		<h1>#art.name#</h1>
	</div>
	</cfoutput>

	<cfoutput>
	<div data-role="content">	
		<b>Artist: </b> #art.artist#<br/>
		<b>Price: </b> #dollarFormat(art.price)#<br/>
		#art.description#
		<p/>
		<img src="#art.image#">
	</div>
	</cfoutput>

</div>

</body>
</html>

This page is even simpler. We just get the art detail and render it within the page. Nothing fancy at all - not yet anyway.

You can demo this here: http://www.coldfusionjedi.com/demos/artbrowser/v1/

Ok, ready to go crazy? I decided on two main changes to my application. First, art pieces would have a new button, Add to Favorites (or Remove from Favorites). Once clicked, I'd use a jQuery Mobile dialog to prompt the user if they were sure. (Normally I hate crap like that. Don't second guess me. But I wanted to try dialogs in jQuery Mobile.) If the user confirms the action, I then simply update local storage to store the value. Since you can only store simple values, I used built in JSON features to store complex data about the art piece (really just the ID and name).

On the home page, I had, what I thought, was a simple thing to do. When the page loads, simply fill out a dynamic list of the user favorites. Here's where things really took a turn for the worst for me. I want to give a huge shout out to user aaraonpadoshek who helped me out on the jQuery Mobile forums. I'll show the new home page and explain what changed.


<cfset categories = application.artservice.getMediaTypes()>

<!DOCTYPE html> 
<html> 
	<head> 
	<meta name="viewport" content="width=device-width, initial-scale=1"> 
	<title>Art Browser</title> 
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
	<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
	<script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
	<script>
	//Credit: http://diveintohtml5.org/storage.html
	function supports_html5_storage() {
	  try {
	    return 'localStorage' in window && window['localStorage'] !== null;
	  } catch (e) {
	    return false;
	  }
	}
	function supports_json() {
	  try {
	    return 'JSON' in window && window['JSON'] !== null;
	  } catch (e) {
	    return false;
	  }
	}
	
	$(document).ready(function() {

		//only bother if we support storage
		if (supports_html5_storage() && supports_json()) {

			//when art detail pages load, show button
			$('div.artDetail').live('pageshow', function(event, ui){
				//which do we show?
				var id = $(this).data("artid");
				if (!hasInStorage(id)) {
					$(".addToFavoritesDiv").show();
					$(".removeFromFavoritesDiv").hide();
				}
				else {
					$(".addToFavoritesDiv").hide();
					$(".removeFromFavoritesDiv").show();
				}
			});

			//When clicking the link in details pages to add to fav
			$(".addToFavoritesDiv a").live('vclick', function(event) {
				var id=$(this).data("artid");
				$.mobile.changePage("addtofav.cfm", {role:"dialog",data:{"id":id}});
			});

			//When clicking the link in details pages to add to fav
			$(".removeFromFavoritesDiv a").live('vclick', function(event) {
				var id=$(this).data("artid");
				$.mobile.changePage("removefromfav.cfm", {role:"dialog",data:{"id":id}});
			});

			//When confirming the add to fav
			$('.addToFavoritesButton').live('vclick', function(event, ui){
				var id=$(this).data("artid");
				var label=$(this).data("artname");
				addToStorage(id,label);
				$("#addToFavoritesDialog").dialog("close");
			});

			//When confirming the remove from fav
			$('.removeFromFavoritesButton').live('vclick', function(event, ui){
				var id=$(this).data("artid");
				var label=$(this).data("artname");
				removeFromStorage(id,label);
				$("#removeFromFavoritesDialog").dialog("close");
			});
			

			$('#homePage').live('pagebeforeshow', function(event, ui){
				//get our favs
				var favs = getStorage();
				var $favoritesList = $("#favoritesList");
				if (!$.isEmptyObject(favs)) {
					if ($favoritesList.size() == 0) {
						$favoritesList = $('<ul id="favoritesList" data-inset="true"></ul>');
						
						var s = "<li data-role=\"list-divider\">Favorites</li>";
						for (var key in favs) {
							s+= "<li><a href=\"art.cfm?id="+key+"\">"+favs[key]+"</a></li>";
						}
						$favoritesList.append(s);
						$("#homePageContent").append($favoritesList);
						$favoritesList.listview();
					} else {
						$favoritesList.empty();
						var s = "<li data-role=\"list-divider\">Favorites</li>";
						for (var key in favs) {
							s+= "<li><a href=\"art.cfm?id="+key+"\">"+favs[key]+"</a></li>";
						}
						$favoritesList.append(s);
						$favoritesList.listview("refresh");
					}
				} else {
					// remove list if it exists and there are no favs
					if($favoritesList.size() > 0) $favoritesList.remove();
				}
			});		
					
			//Adding to storage
			function addToStorage(id,label){
				if (!hasInStorage(id)) {
					var data = getStorage();
					data[id] = label;
					saveStorage(data);
				}
			}	
			
			//loading from storage
			function getStorage(){
				var current = localStorage["favorites"];
				var data = {};
				if(typeof current != "undefined") data=window.JSON.parse(current);
				return data;
			}
			
			//Checking storage
			function hasInStorage(id){
				return (id in getStorage());
			}		

			//Adding to storage
			function removeFromStorage(id,label){
				if (hasInStorage(id)) {
					var data = getStorage();
					delete data[id];
					console.log('removed '+id);
					saveStorage(data);
				}
			}	
			
			//save storage
			function saveStorage(data){
				console.log("To store...");
				console.dir(data);
				localStorage["favorites"] = window.JSON.stringify(data);
			}
	
		}		

	});
	</script>

</head> 
<body> 

<div data-role="page" id="homePage">

	<div data-role="header">
		<h1>Art Browser</h1>
	</div>

	<div data-role="content" id="homePageContent">	
		<ul data-role="listview" data-inset="true">
			<cfoutput query="categories">
				<li><a href="category.cfm?id=#mediaid#&media=#urlEncodedFormat(mediatype)#">#mediatype#</a> <span class="ui-li-count">#total#</span></li>
			</cfoutput>
        </ul>  
		
	</div>

</div>

</body>
</html>

Ok - a bit more going on here. I'll take it step by step. On top I've got two utility functions taken based on code from the DiveIntoHTML5 site. One checks for local storage support and one for JSON. It's probably overkill for mobile, but it doesn't hurt. Notice that I check both of these functions before I do anything else. It occurs to me that I wrapped up a lot of code in that IF and I should have simply exited the document.ready event handler instead.

I begin by using the "pageshow" event for my art detail page to decide if I should show the "Add to" or "Remove from" buttons. The hasInStorage function is defined later on and is just a utility I wrote for my code to quickly see if a particular art piece is favorited. I'll show that art page in a bit so you can see the HTML differences.

The next two functions listen for clicks on the new buttons. Notice the "vclick" listener. This is not - as far as I know - actually documented. At least 5 of my gray hairs this week came from this. Apparently this is the new way to listen in for click events on multiple devices. It's in the jQuery Mobile blog, but again, it isn't documented. When I went live and tested my code, it had worked fine in Chrome but not at all in iOS or Android. Apparently this is why. Very frustrating! Notice - when you click, I use the built in changePage utility to load a page. But this is the cool thing - I can turn this into a dialog by adding a role attribute. So basically - addtofav.cfm and removefromfav.cfm are normal pages - but because of how I tell jQuery Mobile to load them, turn turn into dialogs. Sweet.

Moving down - the next two event handlers are for the actual confirmations. Nothing special there. They call my utility functions defined later on to change local storage values.

Ok - so here is the part I really struggled with and where aaraonpadoshek helped. I needed a way to say, "When the page loads, write out the list." Unfortunately, the pageshow event, which runs every time, also runs before the page initializes. Read that again - it runs every time the page shows and also before it's even fully drawn. There's a pageinit method which does run after the page initializes but only runs once. So when I used pageshow and tried to change my list, I got an error because jQuery Mobile hadn't added the magical unicorn dust yet to make it pretty. When I used pageinit it worked... once. Here's where Aaron's code helped. Notice we have pagebeforeshow being listened for now. It now detects in the list exists in the DOM. If it doesn't, we create it and initialize it ourselves as a list view. If it does exist, we update it using refresh. I'll be honest and say this still is a bit... fuzzy... in my mind. But it works! And that's good enough for me. I've got a bit of DRY going on there with the display but I'll fix that later.

Moving down - you can now see my functions for working with local storage. To be honest, it's all pretty trivial. I've got a function to add and remove, to check for existence, and to get and persist. I added wrappers for them because I'm using JSON to store the data. Now let's look at the update to art.cfm:


<div class="addToFavoritesDiv" style="display:none"><a href="" data-role="button" data-artid="#art.id#">Add to Favorites</a></div>
<div class="removeFromFavoritesDiv" style="display:none"><a href="" data-role="button" data-artid="#art.id#">Remove from Favorites</a></div>

That's the two buttons. Notice they are both hidden by default. Also note the use of data-artid to store in the primary key I'll use later. Now let's look at addtofav.cfm. I won't bother with the remove as it's pretty much the same.


<cfparam name="url.id">
<cfset art = application.artservice.getArtPiece(url.id)>

<!DOCTYPE html> 
<html> 
	<head> 
	<title>Add to Favorites?</title> 
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
	<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
	<script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
</head> 
<body> 

<div data-role="page" id="addToFavoritesDialog">

	<div data-role="header">
		<h1>Add to Favorites?</h1>
	</div>

	<div data-role="content">	
		<p>
		<cfoutput>
		<a href="" data-role="button" data-theme="b" data-artid="#url.id#" data-artname="#art.name#" class="addToFavoritesButton">Yes!</a>
		<a href="art.cfc?id=#url.id#" data-rel="back" data-role="button">No thank you</a>
		</cfoutput>
		</p>	
	</div>

</div>

</body>
</html>

Nothing fancy here either. Just simple content with some buttons. Here's a shot of the art view:

And here's a shot of the dialog.

And finally - the new home page:

Whew! Done. By the way, I'll also point out another issue I had. When I first tested on a mobile device, the text was incredibly small. I got a nice tweet from @jquerymobile pointing out that in beta1, you need to include a new meta tag in your page templates:


<meta name="viewport" content="width=device-width, initial-scale=1"> 	

Adding that helped right away. Ok - that's it. I've included a zip below and you can play with this yourself via the uber Demo button. Enjoy.

Download attached file.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Eddie Monge posted on 7/14/2011 at 9:42 AM

I've made a few changes to your JS:
https://gist.github.com/108...
I thought there was a way to do a diff on gists.github.com but forgot how (if it existed)

Comment 2 by Raymond Camden posted on 7/14/2011 at 2:31 PM

It looks like - mainly - a bit tighter in the event handlers, right?

FYI (to all) - about to go on a 9 day vacation so may be a bit slow to respond.

Comment 3 by SteveOfSP posted on 7/14/2011 at 7:28 PM

Running this online (FF) hangs when you drill down to the actual art. But still very cool. Thanx.

Comment 4 by Raymond Camden posted on 7/24/2011 at 6:47 PM

Could be my console.log usage. Are you not running Firebug? Does it work fine in Chrome?

Comment 5 by Sholto Maud posted on 9/22/2011 at 7:11 AM

the $('#homePage').live('pagebeforeshow', function(event, ui){ ...
doesn't work for me when I first visit the page, the favourites list doesn't render. If I go back to the home page from an internal page, the favourites list does render and works beautifully from then onwards. Is there a trick to pagebeforeshow when first landing on the page?

Comment 6 by Sholto Maud posted on 9/22/2011 at 10:20 AM

I'm using jgm beta3 ... and I've found that it works when I remove $(document).ready(function()

Comment 7 by Raymond Camden posted on 9/22/2011 at 2:48 PM

I can see no reason why this would fail to work in b3, but obviously I've not tested it there. At most, document.ready may be firing before JQM has finished marking stuff up, BUT, the live call on the div should work whenever.

Comment 8 by Henry posted on 10/15/2011 at 11:01 PM

i'm so disapointed,that you didnt used simple javascript and for example webdb or indexdb.Couse i making a simular app and i fail :(.Anyway i keep searching to get mine running.

Good work anyway

Comment 9 by Raymond Camden posted on 10/16/2011 at 3:14 PM

I disagree completely with your comment Henry.

First off - "simple JS" - my solution does use JavaScript. So that doesn't make sense.

Secondly - "webdb/indexdb" - first off - indexdb/webdb isn't supported as well as local storage. Secondly, the feature doesn't make sense for what I'm doing. You would use indexdb for storing lots of data that needs a SQL-style search interface. My need was to store a few things that I'd always fetch directly. I'm not saying you _couldn't_ use indexdb here, but I really believe local storage makes more sense.

Comment 10 by Donn posted on 1/7/2012 at 10:25 AM

This is amazing. Keep posting dude!

Comment 11 by Jason Haag posted on 1/19/2012 at 2:24 AM

Excellent tutorial and thanks for sharing! I'm interested in doing the same thing (add to favorites), except don't have a need for cold fusion. I totally agree with you about using local storage for this type of capability. This is an excellent example that many can learn from! Without knowing the syntax for cold fusion I would like to create something similar with just HTML5, CSS, and JavaScript. Rather than using the dynamic variables you created (e.g. data-artid="#url.id#") could I just use static variables instead and it should work, right? But I would have to create a unique dialog for each html page using data-artname and data-artid, rather than it being dynamic for each art item. Great stuff!

Comment 12 by Raymond Camden posted on 1/19/2012 at 2:55 AM

Yep, you can use static HTML.

To your last point about needing N pages for the detail. Technically, you do not. See: http://jquerymobile.com/dem...

Comment 13 by Jason Haag posted on 1/20/2012 at 3:01 AM

Thanks Raymond. Are you referring to the section at the bottom of the link to the jqm documentation, "Passing parameters between pages?"

Comment 14 by Raymond Camden posted on 1/20/2012 at 3:06 AM

No, that entire page. It talks about how to create virtual dynamic pages.

Comment 15 by Jason Haag posted on 1/20/2012 at 3:10 AM

In other words, would one of these plug-ins they mentioned be required?

Comment 16 by Raymond Camden posted on 1/20/2012 at 3:18 AM

Crap, brain fart on my part. You want this URL:

http://jquerymobile.com/dem...

It's the page before the one I sent. Sorry.

Comment 17 by Jason Haag posted on 1/20/2012 at 3:47 AM

That's it! Thanks again!

Comment 18 by Jason Haag posted on 1/21/2012 at 3:20 AM

Raymond, were you able to get this to work in Firefox? I'm seeing the following error using Firebug:

invalid 'in' operand getStorage()
[Break On This Error]

return (id in getStorage());

Not sure if my install of firefox may have an issue or if you are able to replicate this.

Comment 19 by Jason Haag posted on 1/21/2012 at 4:11 AM

This seems to prevent the favorites feature from working in firefox or IE. I'm trying to look to see if there is another way to return the id from getStorage() using jquery.

Comment 20 by Raymond Camden posted on 1/21/2012 at 7:36 PM

What version of Firefox?

You can probably change:

function hasInStorage(id){
return (id in getStorage());
}

to this:

function hasInStorage(id){
var current = getStorage();
return current.hasOwnProperty((id);
}

I'm writing this just in the comment field so it may not be exactly right.

Comment 21 by Jason Haag posted on 1/24/2012 at 12:07 AM

I'm using FF 9.0.1

Tried that, but says current is NULL. I'm seeing the same issue when trying your demo in firefox.

I started down this path because the "Add to Favorites" and "Remove" buttons don't render so it led me to: hasInStorage(id).

Are you able to see something different? Does the demo work in firefox on your end? It works perfectly in chrome and safari on my end.

Comment 22 by Raymond Camden posted on 1/24/2012 at 12:51 AM

Nope, it does not work. I assumed that in operator worked in FF. Let me dig a bit.

Comment 23 by Raymond Camden posted on 1/24/2012 at 12:52 AM

When you tried my mod, did you correct the typo I had above?

Comment 24 by Raymond Camden posted on 1/24/2012 at 12:57 AM

Nevermind, it's a bit deeper. Fixing now.

Comment 25 by Raymond Camden posted on 1/24/2012 at 1:00 AM

Ok, I modified both hasInStorage and getStorage. I think this version is better. Just view source here:

http://www.coldfusionjedi.c...

Comment 26 by Jason Haag posted on 1/24/2012 at 1:35 AM

Hey Ramond, that works in FF now. Was it hanging up on current not being undefined (double negative)? I'm new to jquery so the syntax still throws me a bit sometimes.

Just found this plug-in too that helps for checking if your keys are stored: https://addons.mozilla.org/...

Comment 27 by Raymond Camden posted on 1/24/2012 at 2:22 AM

Yep to your first comment.

As an FYI, there is a Chrome extension for LocalStorage viewing too. One I worked on. :)

https://chrome.google.com/w...

Comment 28 by Jason Haag posted on 1/24/2012 at 6:27 PM

Thanks Ramond! Nice job! Will check out your chrome extension!

Hey, have you tested this on IE? The fav buttons render and I can see that localStorage and JSON are supported in the latest version of IE, but IE does a full page refresh when navigating from the addtofav dialog screen to the categories. I'm guessing it handles jQuery mobile a bit differently and this can most likely be alleviated with some type of $.mobile.changePage() update.

Comment 29 by Raymond Camden posted on 1/24/2012 at 7:30 PM

Nope, didn't bother. But note that I was using jQM Beta 1 for this demo. It may work better with the final release.

Comment 30 by Jason Haag posted on 1/25/2012 at 12:01 AM

I'm using the final release and it's still the same. There must be a way to deal with it using jQM. I'll have to create some test cases and submit as a ticket probably. It has to be something with jquery syntax that IE doesn't like...my guess anyway.

Comment 31 by Jason Haag posted on 3/16/2012 at 4:37 AM

Hey CFJedi, I just noticed that this doesn't work in Windows Phone. Thinking it doesn't like something with the jquery syntax.

I adapted your favorites example and implemented in an app I'm building for a conference: http://gt12.adlnet.mobi

If you go the the schedule and drill down to the sessions you'll see where I incorporated it. Pretty sweet! Do you have an inkling of why it might not work on Windows Phone? The lates OS supports localStorage.

Comment 32 by Raymond Camden posted on 3/16/2012 at 5:06 AM

Hmm. So the best I can recommend is to remove stuff until it works and see if you can pinpoint the line where it breaks. That's what I do when things break for me. You should be able to narrow it down.

Comment 33 by BRIAN FERNANDES posted on 5/24/2012 at 10:55 PM

Hi Jason,

Do you have a sample code for the application.

Comment 34 by Marcio posted on 10/26/2012 at 6:03 PM

Hello Raymond,

Nice tutorial! I have a doubt. Is there a way to copy from Android clipboard to localStorage using jQuery ou native javascript?

Thanks

Comment 35 by Raymond Camden posted on 10/26/2012 at 6:21 PM

No idea. I'd assume not... that seems like it would be a security issue.

Comment 36 by Johan posted on 4/11/2013 at 2:13 AM

Hi, great work, this is what I have been looking for!
I just new at this and I'm working on an new app
and I wonder where you can change to categoryname to something else?
For example "Jewelry", "Painting" and so on...

I didn't found It anywhere in your sample cfm files. Where is those categories saved?
And how do I change it?
I would appreciate it if you could light me in this matter. :)

Comment 37 by Raymond Camden posted on 4/11/2013 at 4:34 AM

Sorry - I'm not quite sure I get you. Are you asking how to change the data? Cuz the data itself is just sample data.

Comment 38 by Johan posted on 4/11/2013 at 11:47 AM

When I open the file index.cfm in dreamviewer I don't see the categories: functional, Jewelry, Painting and so on, how do I change this data/text? For example to Fruit, Vegetables and so on...

Comment 39 by Raymond Camden posted on 4/11/2013 at 3:55 PM

Dreamweaver is a code editor. You understand how ColdFusion works, right?

Comment 40 by Johan posted on 4/11/2013 at 11:11 PM

I started to look at it last night, is it there you program the categories?
not sure how it works together with jqm
jqm i know a bit more about
I wanted to make favorites on my mobile app and i need it to be local in the phone
ive been searching the web for a good solution and yours were the closest to my idea
i simply have learn how this works

Comment 41 by Raymond Camden posted on 4/12/2013 at 6:00 AM

Ah, well, then you are in for a journey. :) Note that you can use any server-side language. I'm primarily a ColdFusion person, but I'm doing more with Node.js lately.

Comment 42 by Johan posted on 4/12/2013 at 11:07 PM

Yes programming is fun so that road is the way to go :)
any chance you could share this favorites files to cf ?
if yes would you please send to my mail?
I would be deeply grateful and maybe I can put thanks in the app info with your name if thats ok ? :)

Comment 43 by Raymond Camden posted on 4/13/2013 at 8:42 PM

The CF code is included in the download.

Comment 44 by Johan posted on 4/14/2013 at 1:59 AM

ok, im confused lol I just started to look at CF but I cant import the files into coldfusion, or am I getting this wrong, if I just load them into cf then I cant find/change the favoritenames, etc. Functional, jewel, painting..and so on

Comment 45 by Raymond Camden posted on 4/14/2013 at 3:07 AM

The code is using a database that ships with CF as sample data. If you don't know about databases, well, um, best I recommend is picking up a CF book (like the one I helped write ;)

Comment 46 by Prathyusha posted on 7/8/2013 at 9:35 AM

Hi, Raymond thanks for sharing i'm looking exactly like this but when i'm using this code it doesn't favorites..can you give me any solution to get out this problem( http://stackoverflow.com/qu... ). Thanks in Advance.

Comment 47 by Raymond Camden posted on 7/8/2013 at 2:02 PM

Are you asking me about your code on the SO question or the code here?

Comment 48 by Prathyusha posted on 7/8/2013 at 2:50 PM

Thanks for replying Raymond..actually i need to get the favorites list then i got your blog your code is working very fine but when i implemented this in my code its not working can you help me to get the solution....Thanks in Advance.

Comment 49 by Prathyusha posted on 7/8/2013 at 2:52 PM

i applied this on my code http://jsfiddle.net/9AWvM/2/

Comment 50 by Raymond Camden posted on 7/9/2013 at 4:10 PM

Well, I'd ask you to be more specific about what exactly is failing. You need to trace it down in the code level and see which portion isn't working right.

Comment 51 by Prathyusha posted on 7/11/2013 at 10:32 AM

not exactly i think in page url when i'm click on the "Add to favourite " button it is not listing anything in the favorites page.

Comment 52 by Raymond Camden posted on 7/11/2013 at 3:41 PM

So step one would be to add a console message to the click handler. Ensure it is being fired when you click.

Comment 53 by Prathyusha posted on 7/12/2013 at 1:07 PM

i tried like an alert to get the page id..but when i'm clicking on the button getting the message but "addToStorage" is not working. I'm i doing any wrong in the storage function.can you plz check it once.

Comment 54 by Raymond Camden posted on 7/12/2013 at 4:03 PM

Uh - trying to understand your English. It sounds like you said that you can confirm the click handler does run, is that right?

Basically - all I can tell you is to try to trace it down to what is failing exactly. I tend to use console.log() as a way to do this. You could also use the step debugger in Chrome.

You really need to do this, not me. If your code is online in a place where I can _run_ it, I will try.

Comment 55 by Prathyusha posted on 7/13/2013 at 11:23 AM

yes i need to do this...https://github.com/luckylakshmi/Exa... i upload a example code here. I used in this HTML5,Jquery,css
you can run this in browser i'm using firefox.

Explanation about the files:
In this home page contains a list when we click on the list items it opens the particular file(.txt files) in a separate page. In that page footer contains bookmark button. when i click on the button it opens a dialog box with "yes" and "no". when we click on "yes" it should add that particular page into "favorites list".If "no" it should display that page only. In home page we have a "Bookmarks" button under header. All these favourites should add in that "Bookmarks" in a list view.

Comment 56 by Raymond Camden posted on 7/13/2013 at 5:51 PM

So as I said - you need to check into where it is failing using something like Chrome DevTools, or Firebug. Please take some time to learn those tools and see if you can diagnose the issue yourself. For example, you said clicking the button opens up a prompt asking for yes/no. You need to confirm that works, Then - check the code that runs when you click yes.

Both Firebug and Chrome DevTools let you pause and step through your JS code. You need to do this yourself though to track down the issue. Once you've done that, you are welcome to ask me why it is failing, but at this point you have not done the investigation yourself and you really need to.

Comment 57 by Prathyusha posted on 7/14/2013 at 7:48 PM

Thank you Raymond but this task is urgent for me. Can you plz check this once.

Comment 58 by Raymond Camden posted on 7/14/2013 at 10:54 PM

Prathyusha, my help here is provided for free, and when I can, and more so when I think it will help others and create good conversation. It isn't my job to do your work for you. I gave you ideas for how to proceed. If it is urgent and you just want it fixed, I understand, but if you wish me to do it for you will need to hire me at my normal rate. You can see my rate on my contact page (http://www.raymondcamden.co....

Comment 59 by Sanghoon posted on 9/9/2013 at 7:18 AM

Thank you very much. It helps a lot!
Dise it work, if I use these setting in phonegap?
I think it's possible, because phonegap uses html5, javascript and those are same.

Comment 60 by Sanghoon posted on 9/9/2013 at 7:28 AM

'Dose' not 'Dise'
sorry for misspelling

Comment 61 by Raymond Camden posted on 9/9/2013 at 2:11 PM

Yep, works just fine.

Comment 62 by Jeff Mastromonico posted on 10/9/2013 at 12:00 AM

Jason Haag #
Jason what you have done with your event site is EXACTLY what i am am trying to do for an event site for our university. care to share some code or some insight? I'm just not understanding how to put it all together.

Comment 63 by Jason Haag posted on 10/10/2013 at 7:36 PM

Sure, send me a message via my social channels: http://about.me/jsonhaag

I will send you the last working version I had used.

Comment 64 by Jorgensen posted on 10/15/2013 at 12:47 AM

Very nice to see an attempt on something that I was about to make (rather poorly) until I found this.

Comment 65 by Thich Ban La posted on 5/19/2014 at 10:37 AM

Thank you very much for the useful tutorial.
I was like blur to every thing until found your post.
(Sorry for the poor English).

Comment 66 by Mo Pages posted on 8/30/2016 at 6:20 PM

The links and attached files are no longer available :(

Comment 67 (In reply to #66) by Raymond Camden posted on 8/30/2016 at 7:41 PM

I corrected the link. The demo is no longer available online though.