27 May 2010

Jquery gradual loading page

Ever wanted to do a google mail, gmail style gradual loading type page. Where the longer something takes the more messages you get.

So for example something taking ages to load would say:

"loading..."

"still loading....."

"sorry this is taking ages, trying to fix it now...."

gradually, over time. Well i worked that out recently with jquery, it's not rocket science but it's a cute bit of code, made all the easier with jquery. Now before i go on, i'm no javascript expert and definitely i'm no jquery expert. In fact i'm only a few weeks into my jquery life. So if you know a better way about this, then do let me know.

Apologies once again for the poor code sampling, i simply can't work well with google blogger and code samples.

<html>
<head>
 <script language="javascript" src="jquery.js"></script>
 <title>Jay loadings</title>
 <script>
  var loadComplete = false;
  
  //straight away load the loading page
  $.ajax({
   url: "loading.htm",
   cache: false,
   success: function(html){
    $("#mydiv").html(html);
    //if thats done and if page still not completed, do a still loading page
    var t1=setTimeout("if(loadComplete == false){$.ajax({url: 'loading2.htm',cache: false,success: function(html){$('#mydiv').html(html);}});}",2000);
    var t1=setTimeout("if(loadComplete == false){$.ajax({url: 'loading3.htm',cache: false,success: function(html){$('#mydiv').html(html);}});}",6000);
   }
  });
  
  //when target.cfm is ready, load it.
  $(document).ready(function(){
   $.get("target.cfm",
    function(data){
    $("#mydiv").html(data);
    loadComplete = true;
   });  
  });  
 </script>
</head>



<div id="mydiv"></div>  

</html>



26 May 2010

HTML5 drag and drop example

Super quick post here, i was at SOTR recently and all excited about trying out me some new HTML 5. Something i've been meaning to do for ages and ages. Anyway i thought the easiest of which looked like the drag and drop feature. Most fun too, and i had no idea that almost all modern up-to-date browsers support most of the new HTML 5 features already.

I just hope they can get things in gear and punch out some standards sooner rather than the 10 year joke that seems to be circulating.



By the way, if you're thinking of checking out HTML 5, this is really cool:
http://html5readiness.com/

Anyway without further a-do here it is:




Super quick post here



<DOCTYPE HTML>
<html>
<head>
<title>Jay JS</title>
<style type="text/css">
.jayzclass{back9round-color:#ff0000; margin: l2px llO2px l2px l2px; padding: 3px 3px 3px 3px;}
.jayzhidden{visibility:hidden;}
</style>

<script language="javascript">
function dragoverHandler(event) {
if (event.dataTransfer.getData('text/plain').indexOf('monster') != -1){
event. preventDefault();
}
}

function dropHandler(event) {
// remove the dragged element
if (event.dataTransfer.getData('text/plain').indexof('monsterl') != -1){
document.getElementById('1').style.visibility = "hidden";
document.getElementsyId('4').style.visibility = "visible";
}
else if (event. dataTransfer.getData('text/plain'). indexof('monster2') != -1){
document.getElementById('2').style.visibility = "hidden";
document.getElementById('5').style.visibility = "visible";
}
else if (event.dataTransfer.getData('text/plain').indexof('monster3') != -1){
document.getElementById('3').style.visibility = "hidden";
document.getElementById('6').style.visibility = "visible";
}
</script>

</head>

<body>
<p>what monsters do you like?</p>
<table border="O">
<tr>
<td>
<div id="1"><img src="monster1.jpg" draggable /></div><br/>
<div id="2"><img src="monster2.jpg" draggable /></div><br/>
<dlv id="3"><img src="monster3.jpg" draggable /></div><br/>
</td>

<td width="300">&nbsp;</td>
<td>
<div id="4" class="jayzhidden"><img src="monsterl.jpg" draggable /></div><br/>
<div id="5" class="jayzhidden"><img src="monster2.jpg" draggable /></div><br/>
<div id="6" class="jayzhidden"><img src="monster 3.jpg" draggable /></div><br/>
</td>
</tr>
</table>

<div class="jayzclass" id="dropzone" ondragover="dragoverhandler(event); return false;" ondrop="dropHandler(event); return false;" 7> Give me your monsters, i will eat them<br/><br/>
</div>
</body>
</html>

26 March 2010

Google App Engine and Flex

OK so I've previously done a few projects where Flex talks to web-services which is both cool and fun. I started to think i wonder if i can get Google App Engine (GAE) to host my webservice and then Flex to do my front end. Well I'm a big fan of Open BlueDragon (OBD) and their fantastic work with GAE, so i thought I'd give it a spin.

First up the Adobe coldFusion method doesn't yet work, .cfc?wsdl was a no go, not surprising i dread to think what complexity is involved in that. There's something of a discussion of that problem here:

http://groups.google.com/group/openbd/browse_thread/thread/eec7f5664d76f47f?hl=en

However i discovered you can create and host a standard cfc and then call methods in that cfc from a standard cf template.

As the Google groups article suggested, it should be possible to just use OBD to output JSON or wxml or something to output data on a standard webpage minus the HTML. So i thought I'd give that a go.

So on my new GAE app I created a cfc with one function taking one input param and a basic case statement which returned a hardcoded string. Not rocket science. Then i created a simple cfm page to invoke that function and create a json string based on the return.

Something like this:

<cfset jayrox = structNew() />
<cfset jayrox.compName = variables.compName />
<cfset jayrox.compDesc = variables.hello1 />
<cfoutput>#SerializeJSON(jayrox)#</cfoutput>


I committed the above to GAE and then started working on the Flex app. The crux here is two fold.

First the HTTPService


<mx:HTTPService id="personRequest" url="
http://mygaelocation.appspot.com/jsonget.cfm"
requestTimeout="15" useProxy="false"
method="POST" resultFormat="object"
result="personJSON(event)"
fault="server_fault(event);"></mx:HTTPService>


Point that url to your gae cfm page and create a bindable string and a personJSON event handler:


[Bindable]
private var myJSON: String;



private function personJSON(event:ResultEvent):void
{
myJSON = String(event.result);
}


You're almost done, on application initialize run personRequest.send(); and bind a label or textarea to myJSON and you're set.

Second The crossdomain.xml

This is really really important. This took me ages to figure out, Flex and Flash when they're doing remote URL calls are trying to be security conscious. So they don't allow them unless the host (the GAE webroot) has a crossdomain.xml file. So in your war directory in GAE you need to create a crossdomain.xml file and put something like this in there:


<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>


More on this issue here:

http://www.wombatnation.com/2008/04/security-error-accessing-url

And you're done. You can drag and drop your completed .swf into the GAE war directory and there you go, Google App Engine is now hosting a complete end to end data driven Flex app.

When i get time i'll post something about making this a bit more dynamic using GAE data services.

29 January 2010

Link Adobe Flex 3.5 Chart to ColdFusion webservice

As promised, here is a (not very) short blog about how to get Adobe Flex 3.5 to consume a coldfusion cfc based webservice and display it as a chart.

As mentioned in my previous post it's EPIC that Adobe decided to put charting in the SDK. I use the SDK (coz I'm poor) and with it and a little patience you can achieve some amazing Flex apps.

So to do this you'll need the Flex 3.5 SDK, you'll need the Flex data visualization pack and obviously you'll need coldFusion.

I'm sorry for the code here, Google blogger doesn't make posting code easy.

1)The cfc:


<cfcomponent>

<cffunction name="getPersonByDept" access="remote" returntype="query" output="false">
<cfargument name="deptname1" type="string" required="true" />
<cfargument name="deptname2" type="string" required="true" />
<cfargument name="deptname3" type="string" required="true" />
<cfset var myQuery = queryNew('counttt,deptName') />

<cfquery name="myQuery" datasource="jayLocal">
select count(personid) * 100 as [counttt], [deptName]
from [person]
group by [deptName]
having
[deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname1#" />
or [deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname2#" />
or [deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname3#" />
</cfquery>

<cfreturn myQuery />
</cffunction>

</cfcomponent>



I know, I know, the function isn't great, i don't need to pass in 3 separate params, but this is just for illustration purposes. Take this cfc and save it as latestone.cfc in your coldfusion webroot or in a webservices folder. Whatever you fancy. You're going to want to be careful of Application.cfc because it can eat your webservices. You should be able to then open up the wsdl in your browser.
http://localhost/webserrvices/latestone.cfc?wsdl
You should see a bunch of xml data. This is coldfusion doing the hard work for you and describing the webservices offered at this wsdl.
The datasource and query are linked to a ms sql server, a single table called person. It should all be pretty straightforward.



2)The test.cfm:

OK so far so good, lets create a quick test.cfm and make sure the webservice works so far. Create the cfm file and paste in the following code:


<cfobject type="JAVA"
action="Create"
name="factory"
class="coldfusion.server.ServiceFactory">
<cfset RpcService = factory.XmlRpcService />
<cfset RpcService.refreshWebService("http://localhost/webserrvices/latestone.cfc?wsdl")>


<cfinvoke webservice="http://localhost/webserrvices/latestone.cfc?wsdl" method="getPersonByDept" returnvariable="hello2">
<cfinvokeargument name="deptname1" value="development" />
<cfinvokeargument name="deptname2" value="sales" />
<cfinvokeargument name="deptname3" value="marketing" />
</cfinvoke>



<cfdump var="#hello2#" />





OK quick bit of explaining. First and foremost the first paragraph, the JAVA stuff may be the single most useful piece of code when working with webservices in CF. CF does some aggressive caching when it comes to webservices. So if you're in dev mode this code forces CF to keep re-looking. DO NOT leave this code on a production server as it'll slow it right down. But for now it's useful. The second bit of code is a simple cfinvoke based on a webservice consumption.


3)The mxml:

Finally the Flex part. OK So assuming you've downloaded Flex, and tried a helloWorld already you should be able to take the following code and paste it into a .mxml file. Then compile it using the mxmlc command as before. Here's the mxml Flex code:




<?xml version="1.0" encoding="utf-8"?>

<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
viewSourceURL="src/HelloWorld/index.html"
horizontalAlign="center" verticalAlign="middle" initialize="initApp()" backgroundColor="white">


<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.utils.ObjectUtil;
import mx.core.Application;
import mx.validators.Validator;
import mx.managers.CursorManager;
import mx.events.ListEvent;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridListData;
import mx.utils.ArrayUtil;


[Bindable]
private var myDebpts: ArrayCollection;



public function initApp():void {
//onload send webservice
WSgetTasks.getPersonByDept.send();
}


private function server_fault(event:FaultEvent):void{
//on error, show...an error message!
Alert.show(ObjectUtil.toString(event.fault));
}


private function returnLoadTasks(evt:ResultEvent):void {
//when webservice returns, we grab the results and stick it in the bindable myDebpts
myDebpts = WSgetTasks.getPersonByDept.lastResult;
}


]]>
</mx:Script>

//This is the crus of the app, the webservice call. the operation tells it what method to call and the request stuff is the parameters, that simple!
<mx:WebService id="WSgetTasks" wsdl="http://localhost/webserrvices/latestone.cfc?wsdl" fault="server_fault(event);" result="returnLoadTasks(event)">
<mx:operation name="getPersonByDept">
<mx:request>
<deptname1>development</deptname1>
<deptname2>sales</deptname2>
<deptname3>marketing</deptname3>
</mx:request>
</mx:operation>
</mx:WebService>


<mx:Panel title="Users By Department" height="300" width="400">
//the chart
<mx:ColumnChart id="myChart"
dataProvider="{myDebpts}"
height="100%"
width="100%"
showDataTips="true">


//this bit is confusing but it works!
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{myDebpts}" categoryField="DEPTNAME" />
</mx:horizontalAxis>

<mx:series>
<mx:ColumnSeries yField="COUNTTT" xField="DEPTNAME" displayName="Department Name" />
</mx:series>
</mx:ColumnChart>


<mx:Legend dataProvider="{myChart}"/>
</mx:Panel>


</mx:Application>





There we go. Hopefully the comments provide some clarity, again I'm sorry Google blogger does such a poor job of showing the code properly. To talk you through it briefly, on app initialize the initApp() is called, this triggers the webservice. The mx:WebService calls the cfc which we defined as a webservice. It uses the mx:operation and the mx:request as parameters, obviously you can bind these to a text field or something. Then on completion the result runs the returnLoadTasks() function which loads the lastresult into the bindable arraycollection. This arraycollection is bound to the chart with the appropriate x and y axis names.

4)Display the generated flash file:

Done. Compile this and flex will spit out a lovely flash file. Copy this to your web directory somewhere and add the following to output the flash file:



<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="100%" height="100%">
<param name="movie" value="wschart.swf">
<param name="quality" value="high">
<embed src="wschart.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="100%" height="100%"></embed>
</object>




21 January 2010

Update: Charting available in Flex

A while ago i posted an entry saying charting was not available to Flex users of the SDK. While i was upset (charting is cool) I understood that Adobe wanted to attract users to their Flex Builder (purchased) product over the free SDK. Well in the latest version i discovered to my surprise the SDK can now support charting. This is awesome, hats of to Adobe, it works great and looks amazing, and all for free, grata, no money!

Here's a very brief example:

1) Download the SDK and the data visualization pack (currently flex version 3.5):
http://www.adobe.com/cfusion/entitlement/index.cfm?e=flex3sdk

2) Unzip install, etc, rtfm.

3) Create a blank text file with the extension .mxml

4) type the following code:



5) type something along the lines of this in a cmd window

C:\Adobe\Flex3\bin>mxmlc --strict=true --file-specs C:\flexie\chartTest.mxml

**should be obvious the first bit is cmd window telling me what dir i'm in, then the mxmlc is the executable to use for compiling and the rest is jarg, then the last bit is the location of my mxml code file.

6) This should deploy a .swf file to your code location. The swf file is then your flex app with some pretty little charts available!

I'll blog later with how to link these charts to something useful like a cf webservice.

Congrats Adobe on putting charts in the sdk, nice one.