Doing form Post in Spry (2)

Last week or so I blogged about doing form postings with Spry. I was asked to provide a bit more documentation so I thought I'd show a slightly more detailed example.

First lets start with a very simple form:

<form> number one: <input type="text" name="one" id="one"><br> number two: <input type="text" name="two" id="two"><br> </form>

This form has two simple text fields named one and two. I want to use Spry to send the values of these two fields to the server. First lets add a simple button:

<input type="button" value="Add" onClick="doAddPost()">

This simply fires off a JavaScript function. I'm going to break the function up and explain each and every line to make it as clear as possible. First, start the function.

function doAddPost() {

We need to know where we will be posting the form, so next I define the URL:

var url = "moon.cfm";

Now I need to grab the values I want to post. Normally with a submit button you don't have to worry about this. The browser simply sends all the form fields. In this case though I have to specify the fields manually. First I'll grab the value of the form field, one, using the Spry/Prototype $() shortcut:

var one = $("one").value;

Then I'll grab the value from the second form field:

var two = $("two").value;

The form post data must be sent like a query string: foo1=value1&foo2=value2. Again, I have to do this by hand:

var formData = 'one='+one+'&two='+two;

Next I encode any values in the string, like spaces or other special characters:

formData = encodeURI(formData);

So the last thing we do is run the Spry code that will handle the form post. I talked about this more in the last post so I won't spend a lot of time on it.

Spry.Utils.loadURL('POST', url, true, resFunc, {postData: formData, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}});

The first argument defines the type of request (GET or POST). The second argument is the URL value I defined earlier. The third argument defines if the call is asynchronous or not. The fourth argument defines a function to run with the result of the HTTP call. Lastly there is a structure of arguments that define the request. Again I have to thank Keith for figuring this out.

So here is the function again all in one code block:

function doAddPost() { var url = "moon.cfm"; var one = $("one").value; var two = $("two").value; var formData = 'one='+one+'&two='+two; formData = encodeURI(formData); Spry.Utils.loadURL('POST', url, true, resFunc, {postData: formData, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}}); }

So how do we handle this server side? We have a few options. As I mentioned, the loadURL function lets you define code to run with the result. So whatever the server returned I can work with in JavaScript. This can be either a string or XML or WDDX. To make it easier I'll just return a simple string:

<cfsetting enablecfoutputonly=true> <cfparam name="form.one" default="0"> <cfparam name="form.two" default="0">

<cfif isNumeric(form.one) and isNumeric(form.two)> <cfoutput>#form.one+form.two#</cfoutput> <cfelse> <cfoutput>0</cfoutput> </cfif>

Obviously there isn't anything too complex here, just the addition of two numbers. I take the result and simply output it directly to the client requesting the data. With me so far?

Now let's return to JavaScript and work with the result. I had specified the a function named resFunc would handle the result. The function is all of 4 lines:

function resFunc(request) { var result = request.xhRequest.responseText; $("result").innerHTML = "Result was: " + result; }

Spry automatically passes a collection of data back. The information I'm interested in resides in xhRequest.responseText. Once I have that, I can write out the result in the browser.

So I had mentioned more than once I wanted to make this process a bit simpler. Here is my first draft at it:

function doFormPost(url,formlist,resfunc) { var formdata = ''; var formarray = formlist.split(','); for(var i=0; i < formarray.length; i++) { formdata+='&'+formarray[i]+'='; var fValue = $(formarray[i]).value; formdata+=fValue; } formData = encodeURI(formdata); Spry.Utils.loadURL('POST', url, true, resfunc, {postData: formdata, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}}); }

This lets you pass in a url and a list of form fields to post. The third argument is optional. So to do a Spry post you can do this instead of the button and custom function I had before:

<input type="button" value="Add3" onClick="doFormPost('moon.cfm', 'one,two',resFunc)">

As I said though this is just a first draft. Right now it assumes just text fields.

Archived Comments

Comment 1 by Mark posted on 1/30/2007 at 2:49 PM

Thank you sooooo much Ray, I look forward to more :) I'm printing and putting the jug on now.

Comment 2 by Raymond Camden posted on 1/30/2007 at 4:32 PM

Putting the jug on?

Comment 3 by Sid Wing posted on 1/30/2007 at 6:57 PM

Hmmmmmm.... jug... last time I heard someone "putting the jug on" they were placing it under the spigot of a STILL!!! (grins)

Anyway... nice stuff, Ray... between Spry and Flex2 my brain has been pretty stuffed the last few weeks. I HATE being behind the learning curve.

Comment 4 by Mark posted on 1/30/2007 at 11:51 PM

Now now, no still here lol. I'm in New Zealand so I guess it's a saying we have that you folk don't. It means I'm boiling some water for a cup of coffee or tea :) Nothing sinister, I promise.

Thanks again Ray, you are a life saver. Before I try, will this pass multiple checked check boxes to coldfusion the normal way?

Comment 5 by Raymond Camden posted on 1/31/2007 at 12:10 AM

This sample code only works with text fields. I'm going to update it eventually to work with all form fields.

Comment 6 by Mark posted on 1/31/2007 at 5:14 AM

Ray, Thanks to your tutorial and a little googling, I got this puppy working, it's made my day.

// delete images action function
function deleteImages() {
var url = "img-del.cfm";
var vaultImgFile = document.imgForm.vaultImgFile;
var formData = "vaultImgFile=";
for (i = 0; i < vaultImgFile.length; i++){
if (vaultImgFile[i].checked == true){
formData = formData + vaultImgFile[i].value + ",";
}//ends IF
}//ends FOR
// strip last comma
formData = formData.substr(0,formData.length-1);
// encode for spry
formData = encodeURI(formData);
Spry.Utils.loadURL('POST', url, true, delComplete, {postData: formData, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}});
}
function delComplete(request) {
var result = Spry.Utils.encodeEntities(request.xhRequest.responseText);
$("respContent").innerHTML = "Result was: " + result;
// reset status text area
setTimeout("clearVaultImageResults()",10000);
// reload image list
dsVaultImages.setURL("images.cfm?nocache="+d.getSeconds());
dsVaultImages.setXPath('images/image');
dsVaultImages.loadData();
}

Cheers.
Mark.

Comment 7 by Massimo Foti posted on 1/31/2007 at 10:30 AM

Extract form field value this way can be time consuming. That's why I wrote a JavaScript library for forms that, among other features, let you extract and "serialize" field's value from any form. You can see it in action here
http://www.massimocorner.co...

Hope it could help

Massimo

Comment 8 by Kate Juliff posted on 2/17/2007 at 5:21 AM

Excellent!!!

I can understand it all but for one part that will be obvious to anyone with a brain and knowledge of Java,

"Spry automatically passes a collection of data back. The information I'm interested in resides in xhRequest.responseText. Once I have that, I can write out the result in the browser."

HOW to I display the reasult?

I have it all working
see http://www.coolabah.com/spr... (underneath the large photo.

But how can I display the actual result????

Comment 9 by Raymond Camden posted on 2/17/2007 at 6:56 AM

There are a few ways to display something. One way is like so:

Assume foo is the id of a div:

<div id="foo"></div>

Then in JS you can do:

var mydiv = document.getElementById("foo");
mydiv.innerHTML = "some stirng";

This will write out some string as the contents of the div.

Comment 10 by Kate Juliff posted on 2/17/2007 at 7:14 AM

OK. I think I'm missing something.

On my page I have these functions as per your example
function doFormPost(url,formlist,resfunc) {
var formdata = '';
var formarray = formlist.split(',');
for(var i=0; i < formarray.length; i++) {
formdata+='&'+formarray[i]+'=';
var fValue = $(formarray[i]).value;
formdata+=fValue;
}
alert(formdata);
formData = encodeURI(formdata);
Spry.Utils.loadURL('POST', url, true, resfunc, {postData: formdata, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}});
}
function resFunc(request) {
var result = request.xhRequest.responseText;
$("result").innerHTML = "Result was: " + result;

}

doFormPost is called onclick.

Given THAT code, how do I display "result?

Comment 11 by Kate Juliff posted on 2/18/2007 at 5:32 AM

OK I have figured it out to an extent. BUT I'm having trouble with the last parameter of Spry.Utils.loadURL.

In the code snippet below I am trying to pass a value to Spry.Utils.loadURL that will them be passed to resfunc as request. But I cannot work out how to do this.

The function that calls Spry.Utils.loadURL works ok., I test that it is receiving the correct value by using alert(value). But how do I get this value into the argument list of Spry.Utils.loadURL so I can display it?

function doFormPost(url,photoId,resfunc) {
formData = encodeURI(photoId);
Spry.Utils.loadURL('POST', url, true, resfunc, {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"});

}

function resFunc(request) {
var mydiv = document.getElementById("foo");
var result = request.xhRequest.responseText;
$("result").innerHTML = "Result was: " + result ;
mydiv.innerHTML = result;

}

function HandleThumbnailClick(id, photoId)
{

StopSlideShow();
doFormPost('moon.cfm', photoId,resFunc);
dsPhotos.setCurrentRow(id);
ShowCurrentImage();
}

Comment 12 by Raymond Camden posted on 2/18/2007 at 8:42 AM

I think if you want to do this you need to store it in a global javascript variable.

Comment 13 by Kate Juliff posted on 2/18/2007 at 9:00 AM

But in your example it isn't in a global javascript variable.

Comment 14 by Raymond Camden posted on 2/18/2007 at 9:11 AM

I must be misunderstanding you. You want to do a form post, and when you, remember a value such that when the form post is done you can retrieve it. Is that not true.

Comment 15 by Kate Juliff posted on 2/18/2007 at 9:25 AM

I am trying to do exactly what you illustrate in
http://ray.camdenfamily.com...

but instead of passing a form variable, I'm trying to post an argument to the function .

I'm concerned with thew last argument -
{postData: formData, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}}

where I do not have "formdata", but a variable passed to the function.

Comment 16 by Raymond Camden posted on 2/18/2007 at 9:37 AM

formdata is simply a query string I build manually of form values. You can use other values instead, like the one you passed in. But it must be in query string form:

name=value&name=value& etc

Comment 17 by Kate Juliff posted on 2/18/2007 at 9:57 AM

I'm sorry, but I don't understand.

In function doFormPost(url,photoId,resfunc) {
formData = encodeURI(photoId);
Spry.Utils.loadURL('POST', url, true, resfunc, {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"});

}

How do I pass the contents of photoId

Comment 18 by Raymond Camden posted on 2/18/2007 at 10:13 AM

You have a few issues here. First, you didn't follow what I said about name=value (query string) format. You can't just pass a value like photoid. It MUST look like a query string. So if you want to pass photoId, you have ot pass a name for the value as well:

var formData = 'photoId='+photoId;

This says - pass the value photoId, but also give it a name of photoId. In your CFM code that processes this form post, you would use form.photoID.

Then you must encode the value:

formData = encodeURI(formData);

Lastly, you removed the part of loadURL that contained formData:

Spry.Utils.loadURL('POST', url, true, resFunc, {postData: formData, headers: {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}});

See how I pass formData as the value to postData?

Comment 19 by Marcelo Macedo posted on 4/23/2007 at 7:40 PM

A liked your post, its almost what im looking for, maybe you can help-me

I need to send post params.

I can send using this for example:
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php", "/gallery/photos/photo", { method: "POST", postData: "galleryid=2000&offset=20&limit=10", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" } });

Using post data it works,ok, or i can send using your example too, ok, it works.

But in my aplication a create a spry DataSet, and i dont trigger onload, i do that after a few actions.

So, i need to send a post params after i create the Dataset, because i use DataSet.loadData() after some time

But, your example should work, but i couldant populate a spry dataset with my xml result format

Could you help me??

Comment 20 by Raymond Camden posted on 4/23/2007 at 7:55 PM

I'm sorry, but I'm having a hard time understanding your English. Everything after "But in my ..." is a bit greek to me. Can you reword?

Comment 21 by Marcelo Macedo posted on 4/23/2007 at 9:27 PM

=D=D=D=D

Really sory, let´s try again

I need to send post params.

I can send using this for example:
var dsPhotos = new Spry.Data.XMLDataSet("/photos.php", "/gallery/photos/photo", { method: "POST", postData: "galleryid=2000&offset=20&limit=10", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" } });

Using post data it works,ok, or i can send using your example too, ok, it works.

My problem is:
I dont know hot set Post Params, after define a spry DataSet
ex:
var myDs = new Spry.Data.XMLDataSet()
function triggerLater(){
myDs.setXPath("Node/ChildNode")
myDs.setURL(myxml.aspx?aLotOfParams=somevalue);
myDs.loadData()
}

those params ('aLotOfParams') must be POST, because they have a lot of info.

But in your example we heve that function:
function resFunc(request) {
var result = request.xhRequest.responseText;
$("result").innerHTML = "Result was: " + result;
}

than ok, i receive my xml, and i can see it, but i need to populate it in my spry data set
Somethink like:

function resFunc(request) {
var result = request.xhRequest.responseText;
mySpryDataSet=request
}

if you have time,could you help me?

Comment 22 by Raymond Camden posted on 4/23/2007 at 10:18 PM

So are you saying, how do I do a post after my spry data is loaded? If so you simply need to use a dataset observer. The docs cover this and show you how you could run X after data has been loaded.

Comment 23 by Marcelo Macedo posted on 4/25/2007 at 4:21 PM

test

Comment 24 by Marcelo posted on 4/25/2007 at 4:25 PM

No, its not that, by know i made some progress

there is the source: http://www.wl.com.br/spryXM...

So, i have problems to parse my xml data, it works fine in firefox, but not in ie6, do you know why?

Another thing, i just could use it in Firefox when i removed all the white spaces from my XML, Is there some way to keep using spaces??

Thanks for your help!

Comment 25 by H Jaber posted on 12/16/2007 at 12:45 AM

Ray, this is a great post, thank you for it!

I went ahead and modified the example slightly and incorporated Massimo's serializer with it. If anyone is interested in downloading the example, please go to:

http://blog.webexterminator...

Thanks again Ray and Massimo, you guys are the best!

Comment 26 by Matthew Penn posted on 6/8/2008 at 4:39 AM

You might check out the Spry.Utils.submitForm function. It grabs all of the form variables and submits very nicely.

Comment 27 by Massimo Foti posted on 6/8/2008 at 10:16 AM

Spry.Utils.submitForm is a better solution since it handles <select>, radion buttons and checkboxes too. Just be aware it has a bug, it doesn't properly handles <select> tags whenever their value is an empty string. You can see it in action here:

http://www.massimocorner.co...

On a side note, Prototype is affected by a similar bug. Actually, it's worst, since it returns different value for IE and FF. At least Spry is wrong, but consistent :-)

Comment 28 by Raymond Camden posted on 6/8/2008 at 7:03 PM

Thanks - yea - I definitely recommend submitForm now. This post is rather old. :)

@MF - Did you report the bug?

Comment 29 by Massimo Foti posted on 6/8/2008 at 11:52 PM

Yes, I reported the bug

Comment 30 by MikeG posted on 12/2/2008 at 3:15 AM

@Ray
Realizing that this is an OLD post, when I tried to implement I found that you may need to update this line:

First I'll grab the value of the form field, one, using the Spry/Prototype $() shortcut:

To:
First I'll grab the value of the form field, one, using the Spry Spry.$() shortcut:

The updated versions of the js files no longer support just $(), it is now Spry.$() - or atleast, by changing from $() to Spry.$() it worked

Comment 31 by Raymond Camden posted on 12/2/2008 at 3:36 AM

Good point. I'm feeling a bit lazy though so I assume folks will scan the comments. :) I've got way too many blog posts to make a habit out of updating them all. ;)