A few days I blogged about Adobe's release (and sexy-fication) of the javascript framework Spry 1.6. While I have not had a lot of time to play around with the absolutely unique elements, some cool additions are the improvements they made to the password verification and confirmation widgets. With the root password widget, the developer can create a pretty robust set of validation rules for user-entered passwords, such as setting minimum and maximum lengths, required special characters/numbers, etc. The best part is that the Spry framework makes these validations incredibly easy to implement on a normal HTML form. For example, here is an example password field I have created:
That's it. Basically, the entire password widget is a span wrap on the password field. Within this, special validation messages can be defined. On this example, I have set an error message for "required," "minimum characters" and "password strength".
On the function side, the following is all that is required to fully validate this field:
Basically, I simply pass the ID of the widget ("passwordValidation", the ID I gave to the span above) to the Spry.Widget.ValidationPassword() function and then define the various rules that I want to apply to it. I finish the function call with the action I want to trigger the function (here, "blur"). That's it--very simple.
To further round out my example, I have also included a password confirmation field, a required security question field, and a custom-validation zip code field. But most interesting (at least to me) is the functionality on the email field. In addition to validating that the user has entered a syntactically correct email address (that is, one containing an "@" followed by "domain.com"), it also makes an asynchronous call to a ColdFusion component to check whether or not the email exists in the database. It finishes up with displaying a message depending upon the result of the component call. I do this with the following:
Here, I am simply getting the values of the email input field, as well as clearing out any values that exist in the "emailVerification" field. After this, I pass the value of the email field to my component. The component queries the database, evaluates the input, and then returns the status of the email lookup. Once returned, loadURL() fires the callback function "emailResult", listed below.
In a nutshell, this function simply parses the returned value from the component call. If the result is "yes" (i.e., the email exists in the database), I return an error message. If "no," the user is told so.
Now obviously, strikingly absent from this example is any server-side validation. If I were to implement this into an application, I would want to duplicate the various bits of functionality for server-side processing, for the end-user could easily disable javascript in their browser and render all of this fun, flashy stuff entirely moot. Now of course, this means more work for the developer. However, I think it is worth it as the kind of UI options outlined above can make the end-user experience more robust and significantly less frustrating (don't you hate getting error messages AFTER hitting submit and then have to go back and do it all over again?).
Anyway, this is long enough now. Click here to see this code in action!
I know I've been posting alot about Spry lately, but the more I use it, the more I love it! Using the simple-to-implement tools which Spry provides, I am able to spend more time dealing with server-... [more]
And He who sits on the throne said, "Behold, I am making all things new."
In an age in which global warming, climate change and concerns about the viability of our planet's environment ar...
[more]
Just a quick reminder: blogactionday (October 15) is approaching rapidly--next Monday! This is a day where bloggers are encouraged to devote a posting to the environment, regardless of their views o... [more]
On the whole, I tend to be fairly loyal in media technologies. I do what I can to support Adobe --I use ColdFusion, the more]
Within the last six months, my little brother has introduced me to some seriously cool music. One of my favorite bands from this "education" is Emery, a hard-hitting "screamo" band hailing from the ... [more]
A few days I blogged about Adobe's release (and sexy-fication) of the javascript framework Spry 1.6. While I have not had a lot of time to play around with the absolutely unique elements, some cool ... [more]
Over the last week, I have rolled through several chapters of Peacocke's book, "Theology for a Scientific Age," and I will not spend time going over the finer details of each discussion. I simply wi... [more]
Recently, I have blogged about how incredibly cool Adobe's javascript framework---Spry---is and what potential it has for making great dynamic web content. In those posts, I was talking about Spry p... [more]
Growing up in the Wesleyan Church, I've not had tremendously moving experiences with the celebration of communion. In the Wesleyan Church--as in many others--communion is served (by Discipline requi... [more]
Since their self-titled debut in 2000, Rascal Flatts has consistently and with ever-growing force become a presence within the country-pop crossover music scene to be reckoned with. Boasting such awa... [more]
Welcome to my blog. I am often asked what "Exist/Dissolve" means. Well, that is certainly a good question, and I am currently in the process of discovering the answer myself. Prima facie, it strikes me as encapsulating the existensial crisis that is our lives as finite, contingent beings. For a brief moment, we exist, and the next we dissolve into the nothingness of non-existence. From a theological perspective, it is, for me, a sort of ad hoc apologetic for resurrection - i.e., if to exist/dissolve is the human dilemma, there is nothing inherent to the person that guarantees existence, either now or "after" death. Therefore, resurrection is at the same time both the height of absurdity (for it is a notion entirely alien to the paradigm of existence to which we are naturally enculturated) and the only hope for the human to persevere beyond the pale of death.
| deviant monk | |
| mofast-manna | |
| reformed mafia | |
| rose's reasonings | |
| Shawn Dones | |
| scribe |
22 comments logged
Please login to leave a comment
deviantmonk
Knight
55 posts
October 03, 2007 at 08:46:56 AM
deviantmonk awakens from his blog-induced coma and reveals:
wow... I'm not sure there could be anything more boring than this post. Well, besides those of the reformed persuasion arguing eschatology amongst themselves. Spry's at least sexier, unless I can find a pic of either MacArthur or Piper in a thong...
existdissolve
Demiurge
587 posts
October 03, 2007 at 09:01:18 AM
existdissolve retorts to the apparent threat to his livelihood:
Did you at least try the example?
And Piper in a thong is sexy = truth. He's the one who brought sexy back.
deviantmonk
Knight
55 posts
October 03, 2007 at 10:15:57 AM
deviantmonk sighs at still having to communicate through tactile means :
Yes, I tried it. very nice, although, it might be nice to know what security question one is going to be providing an answer for, unless it's meant to be Jeopardy. Cage fight between Piper and Trebek.
tb
Knight
10 posts
October 17, 2007 at 01:47:59 PM
tb responds:
New to spry. I'm working on a coldbox application trying to use it to call a cfc and return a boolean. Based on the return value from the cfc I want to alert the user either 'success' or 'failure'. I am having problems accessing the <cfreturn> value. Is there a way to do this?
Here is my spry load url...
Spry.Utils.loadURL("POST","index.cfm?event=Species.ehSpecies.InsertNavItem&pageName=" + pageName + "&eventName=" + eventName, true, InsertSuccess);
The loadURL calls a handler which in turn calls the cfc that contains an insert statement that looks like this...
<cffunction name="InsertNavItem" access="public" output="true" returntype="boolean">
<cfargument name="txtPageName" type="string" required="false">
<cfargument name="txtEventName" type="string" required="false">
<cfset success = "">
<cftry>
<cfquery name="qInsertNavItem" datasource="unify10d">
INSERT INTO NAVIGATION
VALUES (7, 1, <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.txtPageName#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.txtEventName#">, 'prefix')
</cfquery>
<cfcatch type="database">
<cfset success = "false">
<cfreturn success />
</cfcatch>
</cftry>
<cfreturn success />
</cffunction>
I want to be able to access the "True" or "False" returned by the cfc using spry, without refreshing my page. I've probably thoroughly confused anyone reading this, but would appreciate any help you could provide.
Thanks,
TB
existdissolve
Demiurge
587 posts
October 17, 2007 at 05:41:55 PM
existdissolve checks many lines of code, then responds:
TB--
I am myself quite new to Spry, especially to the data-connectivity side, so I don't know if my answer is a "best practice". With that caveat, here is my suggestion for how to accomplish what you are wanting to do.
To begin, the way CFC's (at least in 7 and below) return data to Spry is somewhat less than helpful. For example, if you specify "returntype=string" and then do a normal "<cfreturn "" />, you will notice, in Firebug for example, that ColdFusion returns a WDDX packet. No good for Spry. And if you simply specify a returntype of "XML", ColdFusion throws in a bunch of extra information [even with whitespace suppressed AND output of "false" on the component and methods] that absolutely kills SpryData's parsing of the returned values.
So, return data from a CFC requires a bit of scrubbing. Here's what I do:
First and foremost, make absolutely sure that "output=no" is explicitly set on both the component tag and the function tag.
Second, make sure to include "<cfsetting enablecfoutputonly="yes" />" after the beginning of the component.
Third, run any method processing as normal. Then, when you are ready to return queries, strings, booleans, etc., wrap it into a xml format like so:
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<email id="no"/>
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="text/xml; charset=UTF-8">
<cfreturn verifyEmail />
I use cfsavecontent to create my variable, but I assume using cfxml would work as well. Anyway, the most important part of all of this is the final cfcontent tag--without this, Spry will break as before, so be sure to include it.
Once I have returned this data in a scrubbed, Spry-friendly format, I do something like this:
function emailResult(request) {
var result = request.xhRequest.responseText;
var xmldom = Spry.Utils.stringToXMLDoc(result);
var verifyEmail=xmldom.getElementsByTagName("email");
Basically, this simply walks Spry through the returned XML data from the CFC and gets the expected value from the appropriate node (here, "email").
Like I said at the beginning, I make no claims that this is a best practice. However, it is a fairly painless way to quickly and easily return data from a component to the asynchronous goodness of Spry.
Let me know how this works out for you, and if you have any links to the code you're working on, I'd love to take a look at it.
existdissolve
Demiurge
587 posts
October 17, 2007 at 06:01:28 PM
existdissolve comes back after fixing terrible code in his blog:
TB--
I noticed at least one issue that will cause problems for you: I think having "output=true" and "returntype=boolean" will not make Spry incredibly happy. While there might be a way to return a boolean value straight to Spry, I'm not sure what it is.
tb
Demiurge
10 posts
October 18, 2007 at 07:25:11 AM
tb responds:
Thanks for getting back to me, your code and comments were very helpful.
So clearly I suck at life cause I am still not getting it to work.
Either I am not quite getting this, or its just not working. It seems to make sense to me, so I am probably overlooking something really stupid.
I have ripped my function apart and put it back together and now have thrown it out and am trying your code. Here is my component page which is a complete plagarism of your code...
<cfcomponent name="species" hint="A security datastore object" output="no">
<cfsetting enablecfoutputonly="yes" />
<cffunction name="InsertNavItem" access="public" output="false" returntype="string">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<email id="no" />
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
</cfcomponent>
Here is my JS
function InsertSuccess(request) {
var result = request.xhRequest.responseText;
var xmldom = Spry.Utils.stringToXMLDoc(result);
var verifyEmail = xmldom.getElementsByTagName("email");
var emailText = document.getElementById('emailVerification');
var emailNode = verifyEmail.item(1);
if (emailNode.getAttribute("id") == "yes")
{
alert("Yes");
}
else
{
alert("No");
}
}
When I try to run this, Firebug throws me a nice little message that reads "emailNode has no properties". This leads me to believe that the creation of the XML is not working properly.
Any ideas?
Thanks again for your help.
tb
Demiurge
10 posts
October 18, 2007 at 07:32:08 AM
tb responds:
Thanks for getting back to me, your code and comments were very helpful.
So clearly I suck at life cause I am still not getting it to work.
Either I am not quite getting this, or its just not working. It seems to make sense to me, so I am probably overlooking something really stupid.
I have ripped my function apart and put it back together and now have thrown it out and am trying your code. Here is my component page which is a complete plagarism of your code...
<cfcomponent name="species" hint="A security datastore object" output="no">
<cfsetting enablecfoutputonly="yes" />
<cffunction name="InsertNavItem" access="public" output="false" returntype="string">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<email id="no" />
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
</cfcomponent>
Here is my JS
function InsertSuccess(request) {
var result = request.xhRequest.responseText;
var xmldom = Spry.Utils.stringToXMLDoc(result);
var verifyEmail = xmldom.getElementsByTagName("email");
var emailText = document.getElementById('emailVerification');
var emailNode = verifyEmail.item(1);
if (emailNode.getAttribute("id") == "yes")
{
alert("Yes");
}
else
{
alert("No");
}
}
When I try to run this, Firebug throws me a nice little message that reads "emailNode has no properties". This leads me to believe that the creation of the XML is not working properly.
Any ideas?
Thanks again for your help.
tb
Demiurge
10 posts
October 18, 2007 at 07:32:22 AM
tb responds:
Thanks for getting back to me, your code and comments were very helpful.
So clearly I suck at life cause I am still not getting it to work.
Either I am not quite getting this, or its just not working. It seems to make sense to me, so I am probably overlooking something really stupid.
I have ripped my function apart and put it back together and now have thrown it out and am trying your code. Here is my component page which is a complete plagarism of your code...
<cfcomponent name="species" hint="A security datastore object" output="no">
<cfsetting enablecfoutputonly="yes" />
<cffunction name="InsertNavItem" access="public" output="false" returntype="string">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<email id="no" />
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
</cfcomponent>
Here is my JS
function InsertSuccess(request) {
var result = request.xhRequest.responseText;
var xmldom = Spry.Utils.stringToXMLDoc(result);
var verifyEmail = xmldom.getElementsByTagName("email");
var emailText = document.getElementById('emailVerification');
var emailNode = verifyEmail.item(1);
if (emailNode.getAttribute("id") == "yes")
{
alert("Yes");
}
else
{
alert("No");
}
}
When I try to run this, Firebug throws me a nice little message that reads "emailNode has no properties". This leads me to believe that the creation of the XML is not working properly.
Any ideas?
Thanks again for your help.
existdissolve
Demiurge
587 posts
October 18, 2007 at 07:33:10 AM
existdissolve thinks he has it:
TB--
The only problem that I see is the returnType on your function. When you try to return a string value from a component, it actually returns a wddx packet. ColdFusion apparently knows how to process this fine, but Spry doesn't.
That is why, I would suspect, you are getting the javascript error. With the WDDX packet being returned, there is not an xml structure for Spry to traverse and so when it gets to actually manipulating the value assigned to "emailNode," there is no usable data for it.
The fix, as far as I can tell, would simply be to change your cffunction returnType from "string" to "xml".
Hope this helps!
tb
Demiurge
10 posts
October 18, 2007 at 08:54:15 AM
tb responds:
Hmm, I changed the returntype to xml and received the same error in the javascript.
existdissolve
Demiurge
587 posts
October 18, 2007 at 09:10:10 AM
existdissolve unfortunately overlooked something obvious:
Ah, I see it. The "access" attribute of the function has to be set to "remote"--this exposes the function to asynchronous access, as well as any other type of remote access (e.g., webservices).
Fingers crossed, but that should do it.
tb
Demiurge
10 posts
October 18, 2007 at 11:58:48 AM
tb responds:
That didnt do it either. I'm at a loss.
existdissolve
Demiurge
587 posts
October 18, 2007 at 12:13:19 PM
existdissolve scratches his head:
The only other thing I can think to check is:
1.) Ensure that "Enable Whitespace Management" is set in CF Administrator.
2.) Turn off all Debugging (i've found that sometimes this interferes).
Do you have this code published somewhere where I can browse to the error and see what is happening in the javascript?
tb
Demiurge
10 posts
October 18, 2007 at 12:26:51 PM
tb responds:
1.) Ensure that "Enable Whitespace Management" is set in CF Administrator. -- This is enabled
2.) Turn off all Debugging (i've found that sometimes this interferes). - I've found the same thing and do not have it turned on.
I dont have this code anywhere you can get to it.
I just tried dumping the result
variable.var result = request.xhRequest.responseText;
into a div to see if the page was coming back correctly and it is throwing a CF error...
An error occured while Parsing an XML document.
Detail: Premature end of file.
I'm not familiar with this enough to know what that really means other than the XML is apparently not building correctly in my cffunction.
Here is my function again...
<cffunction name="InsertNavItem" access="remote" output="false" returntype="xml">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<email id="no">
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
I read a few other sites with posts that are using the toXML function like this....
<cfset toXML = createObject("component", "toXML")>
<cfset usersXML = toXML.queryToXML(GetUserInfoQry, "dataset", "row")>
...but that doesnt seem relevant here because I am not trying to convert a query result to XML.
Thanks again for all your ideas.
existdissolve
Demiurge
587 posts
October 18, 2007 at 12:35:52 PM
existdissolve is confused, but perseveres!:
TB--
I've run across that darn "Premature end of file" error myself.
As a shot in the dark, try wrapping
<email id="no">
in a <cfoutput>.
tb
Demiurge
10 posts
October 18, 2007 at 12:44:23 PM
tb responds:
Ok, that gives me a function that looks like this...
<cfcomponent name="species" hint="" output="no">
<cfsetting enablecfoutputonly="yes" />
<cffunction name="InsertNavItem" access="remote" output="false" returntype="xml">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<cfoutput><email id="no"></cfoutput>
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
</cfcomponent>
And throws a new error which is...
An error occured while Parsing an XML document.
Detail:
XML document structures must start and end within the same entity.
existdissolve
Demiurge
587 posts
October 18, 2007 at 01:00:37 PM
existdissolve apologizes for not catching this earlier:
Ok, scrap the <cfoutput>'s. I think I see one issue that will definitely kill the processing.
Your <email id="yes"> node is not closed. XML is EXTREMELY finicky about proper structure.
So I would close if off like so: <email id="yes" />.
See what that does.
tb
Demiurge
10 posts
October 18, 2007 at 01:23:48 PM
tb responds:
It seems to like this...
<cfcomponent name="species" hint="" output="no">
<cfsetting enablecfoutputonly="yes" />
<cffunction name="InsertNavItem" access="remote" output="false" returntype="xml">
<cfsavecontent variable="verifyEmail">
<?xml version=""1.0"" encoding=""UTF-8""?>
<cfoutput><email id="yes" /></cfoutput>
</cfsavecontent>
<cfset verifyEmail = xmlParse(verifyEmail) >
<cfcontent type="application/xml; charset=UTF-8">
<cfreturn verifyEmail />
</cffunction>
</cfcomponent>
With the <cfoutput><email id="yes" /></cfoutput> like that the CF error goes away.
However, it is still not returning a value to the javascript in the email node
When i set emailNode like this
var emailNode = verifyEmail.item(0); and then try to alert the value, it is null. and when it gets to the if statement Firebug throws the same "emailNode has no properties" error.
function InsertSuccess(request) {
var result = request.xhRequest.responseText;
var xmldom = Spry.Utils.stringToXMLDoc(result);
var verifyEmail = xmldom.getElementsByTagName("email");
var emailNode = verifyEmail.item(0);
alert(emailNode);
if (emailNode.getAttribute("id") == 'yes')
{
alert("Yes");
}
else
{
alert("No");
}
}
I need to turn my eyes away from this for the day. I will sing your praises and start tomorrow with a smile if you have this figured out then.
Thanks again,
TB
existdissolve
Demiurge
587 posts
October 19, 2007 at 05:31:13 AM
existdissolve responds:
TB--
Using your code, I was able to duplicate the error you're getting. Unfortunately, I could only reproduce it when I turned ColdFusion debugging on--turning it back off removed the error. Further, it does not appear that "Enable Whitespace Management" in general settings affects it either way.
I even fiddled with removing the "enablecfoutputonly" and it still didn't produce the error--the only thing that did was when I enabled the debugging.
tb
Demiurge
10 posts
October 19, 2007 at 12:41:23 PM
tb responds:
Ok back on this now.
I've set up my page to output the return value into a textarea and it is coming back with html from the cfadmin login page. So, when I call a cfc, instead of returning the value of the cfc, it is returning the login page. Do you have any other ideas of other settings in cfadmin I might need to change in order to get this working?
existdissolve
Demiurge
587 posts
October 19, 2007 at 12:56:21 PM
existdissolve responds:
It's returning the CFAdmin page? It sounds like you're browsing directly to the component (cfc) and not specifying the function you want to call.
Where in your code are you actually hitting the cfc with loadURL()?