Twitter: raymondcamden


Address: Lafayette, LA, USA

jQuery Mobile - adding Local Storage

07-13-2011 57,749 views Mobile, jQuery, JavaScript, ColdFusion 65 Comments

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.

view plain print about
1<cfset categories = application.artservice.getMediaTypes()>
2
3<!DOCTYPE html>
4<html>
5    <head>
6    <title>Art Browser</title>
7    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
8    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
9    <script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
10</head>
11<body>
12
13<div data-role="page">
14
15    <div data-role="header">
16        <h1>Art Browser</h1>
17    </div>
18
19    <div data-role="content">    
20        <ul data-role="listview" data-inset="true">
21            <cfoutput query="categories">
22                <li><a href="category.cfm?id=#mediaid#&media=#urlEncodedFormat(mediatype)#">#mediatype#</a> <span class="ui-li-count">#total#</span></li>
23            </cfoutput>
24 </ul>
25    </div>
26
27</div>
28
29</body>
30</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.

view plain print about
1<cfparam name="url.media" default="">
2<cfparam name="url.id" default="">
3<cfset art = application.artservice.getArt(mediatype=url.id)>
4
5<!DOCTYPE html>
6<html>
7    <head>
8    <cfoutput><title>Art Category - #url.media#</title></cfoutput>
9    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
10    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
11    <script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
12</head>
13<body>
14
15<div data-role="page">
16
17    <cfoutput>
18    <div data-role="header">
19        <a href="index.cfm" data-icon="home" data-iconpos="notext">Home</a>
20        <h1>#url.media#</h1>
21    </div>
22    </cfoutput>
23
24    <div data-role="content">    
25        <cfif art.recordCount>
26            <ul data-role="listview" data-inset="true">
27                <cfoutput query="art">
28                    <li><a href="art.cfm?id=#artid#">#artname#</a></li>
29                </cfoutput>
30     </ul>
31        <cfelse>
32            Sorry, no art in this category.
33        </cfif>
34    </div>
35
36
37</div>
38
39</body>
40</html>

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

view plain print about
1<cfparam name="url.id">
2<cfset art = application.artservice.getArtPiece(url.id)>
3
4<!DOCTYPE html>
5<html>
6    <head>
7    <cfoutput><title>Art - #art.name#</title></cfoutput>
8    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
9    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
10    <script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
11</head>
12<body>
13
14<div data-role="page">
15
16    <cfoutput>
17    <div data-role="header">
18        <a href="index.cfm" data-icon="home" data-iconpos="notext">Home</a>
19        <h1>#art.name#</h1>
20    </div>
21    </cfoutput>
22
23    <cfoutput>
24    <div data-role="content">    
25        <b>Artist: </b> #art.artist#<br/>
26        <b>Price: </b> #dollarFormat(art.price)#<br/>
27        #art.description#
28        <p/>
29        <img src="#art.image#">
30    </div>
31    </cfoutput>
32
33</div>
34
35</body>
36</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.

view plain print about
1<cfset categories = application.artservice.getMediaTypes()>
2
3<!DOCTYPE html>
4<html>
5    <head>
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    <title>Art Browser</title>
8    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
9    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
10    <script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
11    <script>
12    //Credit: http://diveintohtml5.org/storage.html
13    function supports_html5_storage() {
14     try {
15     return 'localStorage' in window && window['localStorage'] !== null;
16     } catch (e) {
17     return false;
18     }
19    }
20    function supports_json() {
21     try {
22     return 'JSON' in window && window['JSON'] !== null;
23     } catch (e) {
24     return false;
25     }
26    }
27    
28    $(document).ready(function() {
29
30        //only bother if we support storage
31        if (supports_html5_storage() && supports_json()) {
32
33            //when art detail pages load, show button
34            $('div.artDetail').live('pageshow', function(event, ui){
35                //which do we show?
36                var id = $(this).data("artid");
37                if (!hasInStorage(id)) {
38                    $(".addToFavoritesDiv").show();
39                    $(".removeFromFavoritesDiv").hide();
40                }
41                else {
42                    $(".addToFavoritesDiv").hide();
43                    $(".removeFromFavoritesDiv").show();
44                }
45            });
46
47            //When clicking the link in details pages to add to fav
48            $(".addToFavoritesDiv a").live('vclick', function(event) {
49                var id=$(this).data("artid");
50                $.mobile.changePage("addtofav.cfm", {role:"dialog",data:{"id":id}});
51            });
52
53            //When clicking the link in details pages to add to fav
54            $(".removeFromFavoritesDiv a").live('vclick', function(event) {
55                var id=$(this).data("artid");
56                $.mobile.changePage("removefromfav.cfm", {role:"dialog",data:{"id":id}});
57            });
58
59            //When confirming the add to fav
60            $('.addToFavoritesButton').live('vclick', function(event, ui){
61                var id=$(this).data("artid");
62                var label=$(this).data("artname");
63                addToStorage(id,label);
64                $("#addToFavoritesDialog").dialog("close");
65            });
66
67            //When confirming the remove from fav
68            $('.removeFromFavoritesButton').live('vclick', function(event, ui){
69                var id=$(this).data("artid");
70                var label=$(this).data("artname");
71                removeFromStorage(id,label);
72                $("#removeFromFavoritesDialog").dialog("close");
73            });
74            
75
76            $('#homePage').live('pagebeforeshow', function(event, ui){
77                //get our favs
78                var favs = getStorage();
79                var $favoritesList = $("#favoritesList");
80                if (!$.isEmptyObject(favs)) {
81                    if ($favoritesList.size() == 0) {
82                        $favoritesList = $('<ul id="favoritesList" data-inset="true"></ul>');
83                        
84                        var s = "<li data-role=\"list-divider\">Favorites</li>";
85                        for (var key in favs) {
86                            s+= "<li><a href=\"art.cfm?id="+key+"\">"+favs[key]+"</a></li>";
87                        }
88                        $favoritesList.append(s);
89                        $("#homePageContent").append($favoritesList);
90                        $favoritesList.listview();
91                    } else {
92                        $favoritesList.empty();
93                        var s = "<li data-role=\"list-divider\">Favorites</li>";
94                        for (var key in favs) {
95                            s+= "<li><a href=\"art.cfm?id="+key+"\">"+favs[key]+"</a></li>";
96                        }
97                        $favoritesList.append(s);
98                        $favoritesList.listview("refresh");
99                    }
100                } else {
101                    // remove list if it exists and there are no favs
102                    if($favoritesList.size() >
0) $favoritesList.remove();
103                }
104            });        
105                    
106            //Adding to storage
107            function addToStorage(id,label){
108                if (!hasInStorage(id)) {
109                    var data = getStorage();
110                    data[id] = label;
111                    saveStorage(data);
112                }
113            }    
114            
115            //loading from storage
116            function getStorage(){
117                var current = localStorage["favorites"];
118                var data = {};
119                if(typeof current != "undefined") data=window.JSON.parse(current);
120                return data;
121            }
122            
123            //Checking storage
124            function hasInStorage(id){
125                return (id in getStorage());
126            }        
127
128            //Adding to storage
129            function removeFromStorage(id,label){
130                if (hasInStorage(id)) {
131                    var data = getStorage();
132                    delete data[id];
133                    console.log('removed '+id);
134                    saveStorage(data);
135                }
136            }    
137            
138            //save storage
139            function saveStorage(data){
140                console.log("To store...");
141                console.dir(data);
142                localStorage["favorites"] = window.JSON.stringify(data);
143            }
144    
145        }        
146
147    });
148    </script>
149
150</head>
151<body>
152
153<div data-role="page" id="homePage">
154
155    <div data-role="header">
156        <h1>Art Browser</h1>
157    </div>
158
159    <div data-role="content" id="homePageContent">    
160        <ul data-role="listview" data-inset="true">
161            <cfoutput query="categories">
162                <li><a href="category.cfm?id=#mediaid#&media=#urlEncodedFormat(mediatype)#">#mediatype#</a> <span class="ui-li-count">#total#</span></li>
163            </cfoutput>
164 </ul>
165        
166    </div>
167
168</div>
169
170</body>
171</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:

view plain print about
1<div class="addToFavoritesDiv" style="display:none"><a href="" data-role="button" data-artid="#art.id#">Add to Favorites</a></div>
2<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.

view plain print about
1<cfparam name="url.id">
2<cfset art = application.artservice.getArtPiece(url.id)>
3
4<!DOCTYPE html>
5<html>
6    <head>
7    <title>Add to Favorites?</title>
8    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" />
9    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
10    <script src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>
11</head>
12<body>
13
14<div data-role="page" id="addToFavoritesDialog">
15
16    <div data-role="header">
17        <h1>Add to Favorites?</h1>
18    </div>
19
20    <div data-role="content">    
21        <p>
22        <cfoutput>
23        <a href="" data-role="button" data-theme="b" data-artid="#url.id#" data-artname="#art.name#" class="addToFavoritesButton">Yes!</a>
24        <a href="art.cfc?id=#url.id#" data-rel="back" data-role="button">No thank you</a>
25        </cfoutput>
26        </p>    
27    </div>
28
29</div>
30
31</body>
32</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:

view plain print about
1<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

65 Comments

  • Commented on 07-14-2011 at 12:42 AM
    I've made a few changes to your JS:
    https://gist.github.com/1081987/f6203727eb979c715f...
    I thought there was a way to do a diff on gists.github.com but forgot how (if it existed)
  • Commented on 07-14-2011 at 5:31 AM
    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.
  • SteveOfSP #
    Commented on 07-14-2011 at 10:28 AM
    Running this online (FF) hangs when you drill down to the actual art. But still very cool. Thanx.
  • Commented on 07-24-2011 at 9:47 AM
    Could be my console.log usage. Are you not running Firebug? Does it work fine in Chrome?
  • Sholto Maud #
    Commented on 09-21-2011 at 10:11 PM
    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?
  • Sholto Maud #
    Commented on 09-22-2011 at 1:20 AM
    I'm using jgm beta3 ... and I've found that it works when I remove $(document).ready(function()
  • Commented on 09-22-2011 at 5:48 AM
    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.
  • Henry #
    Commented on 10-15-2011 at 2: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
  • Commented on 10-16-2011 at 6:14 AM
    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.
  • Donn #
    Commented on 01-06-2012 at 11:25 PM
    This is amazing. Keep posting dude!
  • Jason Haag #
    Commented on 01-18-2012 at 3:24 PM
    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!
  • Commented on 01-18-2012 at 3:55 PM
    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/demos/1.0/docs/pages/page-...
  • Jason Haag #
    Commented on 01-19-2012 at 4:01 PM
    Thanks Raymond. Are you referring to the section at the bottom of the link to the jqm documentation, "Passing parameters between pages?"
  • Commented on 01-19-2012 at 4:06 PM
    No, that entire page. It talks about how to create virtual dynamic pages.
  • Jason Haag #
    Commented on 01-19-2012 at 4:10 PM
    In other words, would one of these plug-ins they mentioned be required?
  • Commented on 01-19-2012 at 4:18 PM
    Crap, brain fart on my part. You want this URL:

    http://jquerymobile.com/demos/1.0/docs/pages/page-...

    It's the page before the one I sent. Sorry.
  • Jason Haag #
    Commented on 01-19-2012 at 4:47 PM
    That's it! Thanks again!
  • Jason Haag #
    Commented on 01-20-2012 at 4:20 PM
    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.
  • Jason Haag #
    Commented on 01-20-2012 at 5:11 PM
    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.
  • Commented on 01-21-2012 at 8:36 AM
    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.
  • Jason Haag #
    Commented on 01-23-2012 at 1:07 PM
    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.
  • Commented on 01-23-2012 at 1:51 PM
    Nope, it does not work. I assumed that in operator worked in FF. Let me dig a bit.
  • Commented on 01-23-2012 at 1:52 PM
    When you tried my mod, did you correct the typo I had above?
  • Commented on 01-23-2012 at 1:57 PM
    Nevermind, it's a bit deeper. Fixing now.
  • Commented on 01-23-2012 at 2:00 PM
    Ok, I modified both hasInStorage and getStorage. I think this version is better. Just view source here:

    http://www.coldfusionjedi.com/demos/artbrowser/v5
  • Jason Haag #
    Commented on 01-23-2012 at 2:35 PM
    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/en-US/firefox/addon/fir...
  • Commented on 01-23-2012 at 3:22 PM
    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/webstore/detail/bpidlidm...
  • Jason Haag #
    Commented on 01-24-2012 at 7:27 AM
    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.
  • Commented on 01-24-2012 at 8:30 AM
    Nope, didn't bother. But note that I was using jQM Beta 1 for this demo. It may work better with the final release.
  • Jason Haag #
    Commented on 01-24-2012 at 1:01 PM
    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.
  • Jason Haag #
    Commented on 03-15-2012 at 7:37 PM
    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.
  • Commented on 03-15-2012 at 8:06 PM
    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.
  • BRIAN FERNANDES #
    Commented on 05-24-2012 at 1:55 PM
    Hi Jason,

    Do you have a sample code for the application.
  • Marcio #
    Commented on 10-26-2012 at 9:03 AM
    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
  • Commented on 10-26-2012 at 9:21 AM
    No idea. I'd assume not... that seems like it would be a security issue.
  • Johan #
    Commented on 04-10-2013 at 5:13 PM
    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. :)
  • Commented on 04-10-2013 at 7:34 PM
    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.
  • Johan #
    Commented on 04-11-2013 at 2: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...
  • Commented on 04-11-2013 at 6:55 AM
    Dreamweaver is a code editor. You understand how ColdFusion works, right?
  • Johan #
    Commented on 04-11-2013 at 2: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
  • Commented on 04-11-2013 at 9:00 PM
    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.
  • Johan #
    Commented on 04-12-2013 at 2: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 ? :)
  • Commented on 04-13-2013 at 11:42 AM
    The CF code is included in the download.
  • Johan #
    Commented on 04-13-2013 at 4:59 PM
    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
  • Commented on 04-13-2013 at 6:07 PM
    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 ;)
  • Prathyusha #
    Commented on 07-08-2013 at 12: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/questions/17468371/how-to... ). Thanks in Advance.
  • Commented on 07-08-2013 at 5:02 AM
    Are you asking me about your code on the SO question or the code here?
  • Prathyusha #
    Commented on 07-08-2013 at 5:50 AM
    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.
  • Prathyusha #
    Commented on 07-08-2013 at 5:52 AM
    i applied this on my code http://jsfiddle.net/9AWvM/2/
  • Commented on 07-09-2013 at 7:10 AM
    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.
  • Prathyusha #
    Commented on 07-11-2013 at 1: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.
  • Commented on 07-11-2013 at 6:41 AM
    So step one would be to add a console message to the click handler. Ensure it is being fired when you click.
  • Prathyusha #
    Commented on 07-12-2013 at 4:07 AM
    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.
  • Commented on 07-12-2013 at 7:03 AM
    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.
  • Prathyusha #
    Commented on 07-13-2013 at 2:23 AM
    yes i need to do this...https://github.com/luckylakshmi/Examplecode 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.
  • Commented on 07-13-2013 at 8:51 AM
    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.
  • Prathyusha #
    Commented on 07-14-2013 at 10:48 AM
    Thank you Raymond but this task is urgent for me. Can you plz check this once.
  • Commented on 07-14-2013 at 1: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.com/contact.cfm).
  • Sanghoon #
    Commented on 09-08-2013 at 10:18 PM
    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.
  • Sanghoon #
    Commented on 09-08-2013 at 10:28 PM
    'Dose' not 'Dise'
    sorry for misspelling
  • Commented on 09-09-2013 at 5:11 AM
    Yep, works just fine.
  • Jeff Mastromonico #
    Commented on 10-08-2013 at 3:00 PM
    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.
  • Commented on 10-10-2013 at 10:36 AM
    Sure, send me a message via my social channels: http://about.me/jsonhaag

    I will send you the last working version I had used.
  • Commented on 10-14-2013 at 3:47 PM
    Very nice to see an attempt on something that I was about to make (rather poorly) until I found this.
  • Thich Ban La #
    Commented on 05-19-2014 at 1: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).

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty