Its JSON, I swear

I am mostly bogging this so I don't forget this stupid mistake I made. I am using jQuery to make an ajax call to a CFC. The CFC returns json data that I am using to populate a form.

The call worked just find and data was returned. However, for some reason, in JavaScript the JSON data was not being treated as JSON. I spent ages searching for solutions and doing trial and error.

This is the JavaScript call I was making:

view plain print about
1function getDetail(item){
2 $.ajax({
3 url: '/components/packages.cfc?method=getPackageByID',
4 cache: false,
5 type: "get",
6 data: {
7 packageid: item
8 },
9 success: function(data){
10 console.log(data.DATA);
11 }
12 });
13 }

This is the CFC that returned JSON.

view plain print about
1<cffunction name="getPackageByID" access="remote" returnformat="JSON" >
2        <cfargument name="packageid" required="true" type="numeric" >
3        
4        <cfset var getdata = "">
5        
6        <cfquery name="getdata" datasource="#request.dsn#" >
7            select * from package
8            where packageid = <cfqueryparam value="#arguments.packageid#" cfsqltype="cf_sql_integer" >
9        </cfquery>
10    
11        <cfreturn getData>
12    </cffunction>

Knowing what I know (which I started to question) I should have been able to use "data.DATA" to get to the JSON data in the result. However, when I output it to the console I would get "undefined". I also tried, among other things, "data[0]" which got me "{".

The lovely kicker was that the Chrome debugger network tab showed the call return as JSON.

I continued to try anything I could think of to get JavaScript to understand the return as JSON. All I ended up doing was finding a ton of ways to not process JSON.

Finally, I figured something out. It finally dawned on me that JavaScript was processing the data as a string not JSON. The "Intelligent Guess" feature of $.ajax() in jQuery was apparently failing to see the data as JSON.

I then added " dataType: 'json' " to the ajax call. Once I did that everything started working as expected.

If there is a moral here I would say it is to not expect data types to be auto assigned correctly. If you can, define what the data types will be. this will save you pain and anguish later.

Till next time...

--Dave

jQuery Mobile; styling loaded content

With today's dynamic systems getting them to load properly is always a challenge.  Especially if you have content loaded via Ajax after the initial load.  This can be the hardest part.  Even more so, things like jQuery Mobile make it even harder.  This is because jQuery Mobile rewrites the html that is initially loaded to be styled and work properly. 

So, lets take a basic example and figure out how to style some ajax loaded content.

Lets look at a basic example of some jQuery Mobile page. Not thing fancy here, this just creates a basic page with a header and footer with some minor content.

view plain print about
1<!DOCTYPE html>
2<html>
3    <head>
4    <title>Page Title</title>
5    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
6    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
7    <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>
8</head>
9<body>
10
11<div data-role="page">
12
13    <div data-role="header" >
14        <h1>Mail Reader</h1>
15    </div><!-- /header -->
16
17    <div data-role="content">    
18        
19        <div class="ui-grid-a">
20            <div class="ui-block-a" style="width: 25%;'">                
21                <ul data-role="
listview" data-inset="true">
22                    <li data-role="
list-divider">My Email</li>
23                    <li><a href="
test.cfm" id="LoadInDiv" rel="external" class="linkDiv">Inbox</a></li>
24                    <li><a href="
test2.cfm" id="LoadInDiv2" rel="external" class="linkDiv">Outbox</a></li>
25                    <li data-role="
list-divider">Other</li>
26                    <li><a href="
index.html">Feeds</a></li>
27                </ul>
28            </div>
29            <div class="
ui-block-b" style="width: 72%; padding-left: 20px;" id="contentDiv">
30            
31            </div>
32        </div>
33    </div><!-- /content -->
34
35    <div data-role="
footer">
36        <div data-role="
navbar">
37            <ul>
38                <li><a href="
#">Summary</a></li>
39                <li><a href="
#" class="ui-btn-active">Favs</a></li>
40                <li><a href="
#">Setup</a></li>
41            </ul>
42        </div><!-- /navbar -->
43    </div><!-- /footer -->
44</div><!-- /page -->
45</body>
46</html>

 

Rendered it looks like this:

 

So now lets take the base and put a little JavaScript in to it.  This script will handle the click and load some external content.

view plain print about
1<script language="JavaScript">
2$(function(){
3    $('.linkDiv').click(function(event) {        
4        $('#contentDiv').load($(this).attr('href'));
5        return false;
6    });
7});
8</script>

The return from the load call contains this:

view plain print about
1<ul data-role="listview" data-inset="true" data-theme="e">
2    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">12</span></li>
3    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">0</span></li>
4    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">0</span></li>
5    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">0</span></li>
6    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">0</span></li>
7    <li><a href="index.html">This could be a subject</a> <span class="ui-li-count">0</span></li>
8</ul>

When rendered I now get this:

Obviously this is wrong.  The returned content has no styling or any "jQuery Mobile" magic in it.  Even the number is off on the far right.

This happens because jQuery Mobile does not know to style the content. It is not that it can't, it just doesn't know it should.  The content is pulled in after the styling has been applied.  So, the question is, How can I get jQuery Mobile to apply its secret sauce to the loaded content?

Well, this was no simple task.  I tried more things than I can count. Had many more failures than I would have liked to.  At one point I got it to work fairly easily. However, subsequent loads would break the UI.  I finally ran across a forum entry that I pieced together with other findings that gave me enough info to create a solution. 

The first thing was not not use load. Load, while a great way to get content into something was not the right way to go here.  What I I needed was to get the content and store it in a var.  Then I had to "coherse" jQuery Mobile into doing it's magic.

So, a simple modification to the JS and I get the magic I am looking for.

view plain print about
1<script language="JavaScript">
2     $(function(){    
3        $('.linkDiv').click(function(event) {
4            $.get($(this).attr('href'), function(data) {
5                $('#contentDiv').html(data).page();
6                $( "div[data-role=page]" ).page( "destroy" ).page();
7            });
8            return false;
9        });
10    });
11</script>

So what is the big change?  Well, I replaced the load with get.  This allowed me to store the result in a var.  I could then take that return and put it into the div.  Yes, load does that for me in one line.  However, adding the ".page()" to the load chain had no effect.  This way the page() worked. However, to be honest, I have no idea what the page() function does.  I just know it has to be there. The next part of the magic sauce was the next line.  Now just like the page function, I have no idea what this does either.  All I know is that these two lines of code allow me to produce the result below.

 

 

Well, there you have it.  A few magic beans and BOOM.

 

Till next time,

 

--Dave

CFHour.com Mobile

I always love it when sites create a lightweight mobile version of their content. I have had many tries and failure to create a mobile version of cfhour.com. I could just never get certain parts right. However every failure brought me closer to what I was trying to accomplish.

The site is using Mango Blog. To create the mobile version I am using jQtouch and jQuery. This gives me the animation and interaction I am looking for in a familiar JavaScript framework. jQtouch is very easy to work with and is very straight forward in how to implement it. But, once you try and go a little off the reservation it gets a little complicated.

Where I kept getting tripped up was the dynamic loading. Every example I had seen used static content. The minor examples I saw were nothing near what I needed to accomplish. Then, a blog post came though from Ray Camden. He used a technique to load dynamic content I had never thought of.

Using this technique I was off and running. I quickly ran into a couple issues. My first issue was that once dynamic content loaded it would not reload. This was corrected with a configuration setting. After changing this setting I ran into what could be a memory overload. The setting to not cache the remote return causes every remote request to be added to the dom. The previous requests are left behind and no longer referenced.

Now, once I figured out how to get the data out of the database. I had to figure out what posts where shows and not just posts. Then get the comments for each post as well as the url to the mp3 file. All this was fairly simple, with the exception of the mp3 url.

[More]

jQuery dialog with loaded content

I am working on a project where I wanted to load a dialog with detail on the selected item. This seemed fairly straight forward since jQuery is so awesome. However, I had a little trouble digging up a good example. So, after some research and combining multiple examples I got it working.

It is actually very easy to accomplish. Here is how...

First, the div that will become the dialog box. I just stuck this at the bottom of the page.

view plain print about
1<div id="dialog-detail" title="Item Detail">
2</div>

Then the JS code to open the dialog...

view plain print about
1function doDetail(itemID){
2    $("#dialog-detail").load('./eventDetail.cfm?id=' + itemID).dialog({modal: true});
3};

I have a link that calls the "doDetail" function and passes in the id of the selected item. The eventDetail.cfm file processes the id and returns the necessary info into the dialog.

One thing I found that was interesting that was the dialog auto sized to fit the content. Well kinda, it would auto grow the height but not the width. The width stayed the default and a horizontal scroll appeared.

Till next time...

--Dave