This question came in to me via Stefan Richter yesterday on Twitter and I thought I'd use the blog to answer in a bit more detail. He asked:
liking jqm so far but have yet to figure out how to keep my business logic separate from markup using cf for backend)
PhoneGap allows you to take simple HTML and create a mobile application. While we may be used to the idea of having HTML to build out our sites, you have to change your thinking a bit when it comes to a PhoneGap application. Your HTML is running within a wrapper on the device itself. That means any logic built in ColdFusion (or any server side language) is not going to be available to you... directly.
Whereas in the past you could have a simple detail page that queried the database based on a URL parameter, your PhoneGap app is - in ways - like running a HTML file downloaded from the Internet.
This does not mean you can't have dynamic PhoneGap apps. You can. But on the "app side", anything dynamic is going to have to be built in JavaScript. You can certainly build out your business logic using JavaScript.
So that means we give up on building web sites with dynamic technologies like ColdFusion, right? Not at all. If your application is entirely self contained, then you can build it out completely with HTML, CSS, and JavaScript. But if your application needs to share data with others, if it needs business logic that access a central database, then you still need a central server.
A PhoneGap application, using JavaScript, can make XHR requests to a server. As an example, I'm working on a mobile app now for a web site. The web site already has a lot of business logic built. I exposed this using a CFC that I can easily call from the PhoneGap app. The mobile app uses JavaScript for requesting and presenting the data. The central server handles things like authentication and returning the appropriate information based on your request.
If this does not make sense, please post a comment!
Archived Comments
I'm struggling with mobile development as well. One titanic struggle I'm having is how to put it native on the iPad such that they can run the page offline. I'm hoping that I can just use application caching and local database storage, and then sync it when they are back online again. I hope that I don't have to include PhoneGap.
Another struggle is how to sync the data once the user is back online. Right now I just have a loop that does AJAX call after AJAX call, with a counter that counts down the number of rows that still need to be sync'd. A better solution would be to package the data up in a wrapper and send it as one request. Probably a JSON object.
So writing a JQMobile is similar to writing a AJAXifed website then. This would be a site where you can write the pages in any language (ASP, PHP, CFM). You would use AJAX to retrieve data from the server, and pass it back to the page. Your business logic would only be on the server. Data validataion logic would be both on client side (Javascript) and server side.
The thing I'm still missing in this whole picture is this:
Do you still write Form processing pages in CFM for users who have Javascript disabled? Example: If I'm using AJAX to handle form submission, I typically return false in my click function AJAX callback to prevent the button click from processing normally.
Oh, and one minor nitpick: You wrote "...XHR requests..." That's like writing Personal PIN Number. The word Request is already incorporated into XHR... :)
@PS: Any reason why NOT to use PhoneGap?
@PS: Yes, syncing is an issue no matter what platform. The main issue is figuring out your rules - ie, if it exists on server and not on client, does that mean you just copy it down, or does it imply a client delete. Once you figure your rules, implementing it is pretty trivial though. I did a demo of this w/ AIR and SQLite for a preso a year or so ago. I did a super simple logic set - server is always right. And even that was a bit complex to code. (Again though, it was complex in figuring out what to do- not the actual code.)
@Brain: Yes to first paragraph. No to second para - I don't believe you can disable JS in the PhoneGap wrapped app. It's NOT the same as the mobile browser. Last paragraph: Bite me! ;)
> it was complex in figuring out what to do- not the actual code.
I think that writing $.ajax calls is very complex!
I think writing JavaScript is very complex! It's been the hardest language for me to learn.
Let's just say you want to pass a large number of rows up to the server, and let the server worry about the business rules. What's the syntax for doing that?
The reason not to use PhoneGap? I just don't know anything about it. In your video on jQuery Mobile development, you say that it takes 30 seconds to include the bits. While that might be true physically, mentally getting to that points takes days, weeks or months.
I guess I need to learn PhoneGap before I say anything else.
I like the post Ray, its somthing that many people are still a little confused on.
@Brian,
Like Ray stated I don't think you can turn off JS in a PG app. As for form validate it depends on what type of app your doing. You need to make the distinction between "Mobile Website App" and "Mobile App"
The website app would be written in what ever language you prefer (CFM, PHP etc) because the code is running on the server so you could validate like you always would.
Now for the mobile application that is wrapped in PG as Ray stated, all you files are packaged up in the PG app, and PG does not know what to do with CFM pages or PHP etc so you have to rely on XHR (<-- notice I did not add request :) ) to retreave and submit data, its also important to remember with PG we don't have cross domain proxy issues so you can send over normal JSON to you backend etc.
Now with a PG app what you would do is send over your form data to you CFC or what ever and have it take that information and validate it there, if it did not validate correctly then you can return back in a JSON object or what ever the fields that were incorrect and then have the function look for that and run another function to display the error message or something like that
Like Ray had said, the business logic is done with JS on the front end but database stuff and validation inserting etc is still done on your back end server.
Hope that makes sense :)
@PS: I apologize - I've been using JS for so long now it feels simple, and I can definitely see how it would NOT be so easy for others. Thanks for reminding me that it is still difficult for folks. (And to be honest, it's hard for me to. I can do the basics REAL well, but 'large' JS apps are still something I'm struggling with myself.)
As to your second paragraph, when you do a $.ajax, or $.get or $.post (they just wrap $.aajax), you can specify the data to send as an object. You can send large data with $.post. $.get passes data via the query string and there is a hard limit to how much data can be sent. So basically, just use $.post.
As to your third paragraph - fair point - I'm doing a presentation on PhoneGap next month - after that I'll see about doing a recorded version. Would that be something you would pay for?
@Phillip,
When you say a large number of rows are you talking about just sending data to the server?
You would do something like this
// First compile your list of rows to update
var myData = "method=updateData?name=Jim&location="bostin";
$.ajax({
type: "POST",
url: "http://mydomain.com/updated...",
data: myData
}).done(function( msg )
{
alert( "Data Saved: " + msg );
});
Now this is a simple example of sending the data in a JQM / phonegap app, for sending large amounts of data you may want to compile it into a list, send that over to you cfc and do the logic there to parse and insert etc.
As far as PG goes I think one of the best way to get started is using DW 5.5 it makes it really simple to get started, then reading the PG docs on how to access things on the phone (camera etc)
With DW 5.5 its really simple to compile for android because they build that process in for you (you can also use PGBuild to compile off of the PG site)While DW5.5 does not have the most current PG build it still helps out a lot in getting started with that, I think Ray had a post a few days back about this same kind of topic and in the responses there are a lot of good links to some vids etc to help get you started.
Hi Ray (thanks for writing this post bacause of me :-)
My issue is actually more with jQuery Mobile than Phonegap. I checked out your recent presentation on JQM and started building a simple CRUD type JQM app with CF backend.
First hurdle: JQM by default loads all 'pages' (page divs to be precise) via AJAX. I'm used to have most of my CF code outside the html section of my document. Is my only option (when I need to for example restrict access to a page to logged-in users) to add logic to the HTML markup in big CF chunks?
Another quick with JQM (due to its loading of page sections) is that even JavaScript won't run unless it is contained within the page section of a loaded page. This makes things even worse from a maintainability point - you end up with bits of logic everywhere.
Maybe I'm just too new to this and don't see the big picture. Do you have a simple JQM CRUD type sample app somewhere on the shelf? Maybe with user login/session management?
I saw your CFBloggers example in JQM but that also has its CF code outside the HTML markup which I think won't work once you add more and more pages with additional logic on pages 'depper down'.
Correct me if I am totally on the wrong track.
Cheers
Stefan
@Stefan,
Are you trying to build a mobile version of a site or a mobile app?
I'm assuming your building a mobile web app and not a site because you mention CF in the page correct?
Anyhow JQM does allow for you to push everything into multiple page Div's but its not recommended to do that. JQM docs say that each page should be its own file but that here nor there for this topic.
So your first question for restricted access There are a few ways you could tackel that I mean if your building a mobile web app with CFM page restricted access is the same for the most part even with the ajax calls the application scope should still reflect that the page you are calling is restricted (I think :)) Another option could be calling a checkLoggedIn function or whatever where in the beforepageload you call this thing to check the user and if the access is not there then return false.
With JQM normally you would have an external JS file that would hold all your function for your app. eliminating the need to place JS inline of each page, unless you want to load a function or something when that page is called etc but you should be able to put these items in an external file.
The important thing to remember is that with mobile (as stated in other posts) you are really using HTML, css and JS only. Doing CRUD type things will be handled by the back end server but the page rendering is done on the client side, all your CF code will be doing is inserting, formatting etc and returning a JSON object that you then parse out and push to the page. (That is if its a PG app, mobile websites could be cfm pages invoking a cfc etc)
OK, I don't think I need PhoneGap because I don't need access to the native APIs like geolocation and the camera.
I'm also developing my app exclusively for the iPhone, so I'm not too concerned with Android at the moment.
My application is for a barcode scanner where I have to store the barcodes and then upload them to the server once the user gets back online. (I said 'sync' last time, but that was a misuse of the word - I meant 'upload').
@Mike,
In your example you said
> data: myData
Q: If I wanted to use JSON as the vehicle for packaging up the data, what command(s) would I use? Perhaps I should work up an example and ask on StackOverflow.com.
Well the nice thing about using say PG is that you can have your app do barcode scanning using the camera on the phone. And if you choose to in the future deploy on android you may only need to change a few small things in your app to deploy, giving you a single source for deploying on multiple platforms, Also its important to note that PG is not just if you want to access phone features its also if you want to deploy on the market as an app so it will be packaged up in an APK (for android) and deployable like that. You also get things like loading screens etc. Anyhow something to look into if your interested.
I'm not sure I understand the question, are you saying you want to create a JSON list and send that to the server?
I could be wrong but why would you want to send a JSON object to your server for processing?
In my example I'm just sending over what would be say form elements in a post, as Ray had said before you usually will send it over post because you have no size limit,
that being said in some of my apps where I have a lot of data to send back to the backend for processing from the mobile side I put everything into different list and push that to my backend cfc for processing / inserting etc.
I hope that makes sense? Also you said you were building native for iphone but are you using JQM?
Sorry just a little confused.
@Stefan. I mostly prefer the business logic to be on the server because I don't believe all data from the db should be sent to the client if business logic is intended to act as a gatekeeper and decide what is appropriate to show the user. (I'm concious that data sent via XHR can so easily be browsed using various dev tools, most built in to browsers these days, and it should only contain stuff that you're happy for users to see.) CF can take care of the business logic and just send the apprioriate content to the app. Also in some cases it's not apprioriate for users or competitors to have access to the business logic which is revealed within the js code. (Not actually sure if the js can be decoded/viewed in a PhoneGap app?)
However, in some cases you might need app-side business logic. e.g. Selecting vehicles from various specifications - engine size, seats, MPG, etc. As you pick your criteria the available models appear or disappear. For speed that logic should be done in the app (javascript) because it would feel too unresponsive even if XHR is used over a 3G connection. Therefore all data on the vehicles needs to be downloaded to the client as JSON when the appropriate page loads.
So where you end up putting the business logic depends on how sensitive the data is that you're applying the logic to and how responsive your app needs to be when the user interacts with it.
@Stefan: JSON is your friend, especially with CRUD and AJAX!
Let's take an update request for example and see how it would flow.
Client makes a request with $.getJSON for a post with the id 4. The server then responds with JSON corresponding to post 4.
The success callback of the request needs to parse the JSON and put it into a form for editing. A simple example could use $.getJSON("http://www.example.com/posts/4", function(data){ /* Success logic here where data is the returned JSON */ }); , but you may also want to include an error callback as well.
The client updates some data and submits to the server -- A $.post is performed, this time with a JSON object serialized from the updated form and posted to the server. jQuery has several methods available to assist with this. Then the server side app would then parse, validate and apply any necessary business logic to the received JSON.
You can keep your business logic safely locked up in your CF app, while taking advantage of the benefits of AJAX.
A couple of comments to the comments:
@Stefan - I think Mike replied to you well - you can store your logic in a JS file. That's what I'm doing for my big app now.
@Phillip: Small nit picky point - geolocation is built into your browser, so you can do that w/o PhoneGap. :)
Thanks guys, this makes a bit more sense now. Sp basically if I am using a CFC and want to return a recordset in a JQM app then I should use getJSON rather than a cfinvoke, right? Right now I was using cfinvoke and in order to get that to work on subsequent 'pages' I needed to put the cfinvoke inline with the HTML markup to run. Not nice.
Another issue I encountered was using a cflogout combined with a cflocation - the URLwuld remain 'stuck' to the logout page and not actually redirect to the index/login page. I guess this is due to the AJAX-y page loading. Not a showstopper, but definitely another small hurdle.
I can't yet decide if I like this way of building websites but I guess it'll get better as we get used to it. Some parts just feel wrong, for example building HTML fragments inside the JS logic that then get injected into the existing markup. It feels dirty somehow :-)
What I'd like to see (maybe this is already possible?) is to build the equivalent of a Flex view component, put it aside and then just set some properties on it via JS when my data arrives as opposed to building whole chunks of HTML in JS and pushing them into the 'view'.
Do I make sense? Anyone with me? :-)
Stefan, getJSON requires your server side app return a JSON object. (I can't speak on how to generate that from Cf as I am still learning CF.) Otherwise output html and use get, or load.
Also, you can use jquery's hide and show functions to prevent having to build html fragments in your js and update the old element while it is hidden and then reshow it. You can go even further by using clone to duplicate a template fragment.
@Stefan: Right, use getJSON on the jQuery side, but you also want to tell CF to return JSON by adding returnFormat=json in the URL. You don't have to return the JSON yourself - just return data. returnFormat tells CF to encode it for you. See my blog post on CFCs and remote calls.
For handling logouts, your remote CFC can simply throw an error if you call a method that's your supposed to be authenticated for. (Pardon the grammar.) Your AJAX code can handle errors (again, see my blog posts on this).
I know it's been a while but I just wanted to say thanks. I've just revisited by little pet project (it's a Jquery Mobile app which allows to tennis players to confirm their availability for the next game) and it now makes a lot more sense.
For future readers' benefit, my mistake was to mix things like cfinvoke in line with the HTML/JS code. I now realise that doesn't work and whilst I can have my CFC as they are (and return JSON) I need to move the logic of fetching records and doing other CRUD from cfinvoke to AJAX calls. I think that's something I can manage with a bit more digging.
First of all, I will try and recreate my login/logout logic in JS/AJAX - right now that too is a cfinvoke call...
Raymond, thanks for all the examples. Do you have a complete JQM/CF sample app somewhere by any chance..?
I'll make sure to post my progress. The first failed attempt is on github (don't laugh):
https://github.com/stoem/Pl...
Define "complete" ;) I've got a bunch of demos. Not sure what would be complete though. You can look at the mobile version of BlogCFC (not from me, Dave Ferguson built it). The mobile version of CFBloggers.org is also available via the Github repo.
Confuses me even more :-)
Just when I thought I understood the concepts you show me stuff like this
https://github.com/cfjedima...
With cfoutput tags mixed in with JQM list views. This stuff does my head in - am I best advised to try and do all remote data fetching via AJAX, or what's the reason for this app not to do that? Is it just because it's so simple it can get away with 'quick and dirty'?
Not meaning to criticise anything or anyone here, just trying to understand what a best practice for a CRUD based JQM browser based app with CFC backend would look like.
I don't blame you if you think: "wtf is this guy on about...!?" :-)
page refresh fail, sorry for double posting...
So to be clear, I consider the mobile version of CFB to be a mobile friendly website. Not a mobile app. It isn't meant to run offline or remotely. It's part of the site itself. Hence the use of cfoutput, etc.
A PhoneGap version would run in context of a browser on the phone itself. There is no ColdFusion locally. So it would be forced to make Ajax calls for all it's remote data. See my "RSS" demos for PhoneGap for an example of that.
Right, I see what you mean.
Well this is a pet project to teach myself JQM. It's not a mobile version of an existing site, but a pure mobile, browser based app. Maybe I'll wrap it with Phonegap later, but right now it's just HTML, JS and CF.
I've noticed that my desktop approach of mixing CF code in with the HTML markup does not seem to work well with JQM as all the 'pages' are loaded via AJAX and I'd have to inline so much CF code it would be very untidy.
It's a learning curve, and so far slow going. But I'll get there and will post my progress.
Wish me luck.
Remember, we are all learning, so you are not alone. ;)