Posted in ColdFusion | Posted on 11-29-2007 | 10,681 views
Some of the new, cool, hip sites out there have done something rather neat with their login system. If you take a look at Technorati, notice that when you click the Sign In link, a modal window pops up. This lets you login no matter where you in the site. No need to go to another page (thank goodness, since Technorati is slow) and be sent back (hopefully) when done. Can ColdFusion 8 do this? Of course! Let's look at an example.
First off - imagine we have an existing site. One that uses a custom tag for layout (details may be found here). All of our pages use the custom tag. For example:
2
3<p>
4Welcome to our Web 2.0 site.
5</p>
6
7</cf_layout>
(As just a quick warning, I'll be sharing the complete code for all of this at the end of the blog entry, and via a download link.) Our layout custom tag creates a simple navigation table on top:
The first thing I want to do is add a Login link to the menu:
The link above runs the JavaScript function, doLogin, so let's go there next.
2 ColdFusion.Window.create('loginwindow','Login','login.cfm',{center:true,modal:true});
3}
This function simply uses the ColdFusion/Ajax API to create a window. I named it loginwindow, gave it a title, pointed it to a login.cfm page, and passed a few attributes. I could have styled it as well, made it a specific size, etc. But you get the idea. Now let's look at login.cfm:
2<table>
3 <tr>
4 <td>Username:</td>
5 <td><input type="text" name="username"></td>
6 </tr>
7 <tr>
8 <td>Password:</td>
9 <td><input type="password" name="password"></td>
10 </tr>
11 <tr>
12 <td> </td>
13 <td><input type="submit" name="login" value="Login"></td>
14 </tr>
15</table>
16</form>
This is a fairly simple form - but note that I specifically block the form submission. I call yet another JavaScript function, handleLogin. So let's take a look at that:
2 ColdFusion.Ajax.submitForm('loginform','processlogin.cfm',handleResponse);
3}
Once again we have a use of the ColdFusion/Ajax API. The submitForm function will do exactly as it sounds - send an entire form block to a page. My last argument, handleResponse, is the function that will be called with the result. Let's look at processlogin.cfm first:
2<cfparam name="form.username" default="">
3<cfparam name="form.password" default="">
4
5<cfif structKeyExists(form, "login")>
6 <cfif form.username is "paris" and form.password is "hilton">
7 <cfset session.loggedin = true>
8 <cfoutput>good</cfoutput>
9 <cfelse>
10 <cfoutput>bad</cfoutput>
11 </cfif>
12</cfif>
Nothing too complex here. Normally you would call a CFC to handle the authentication. I've never used a hard coded username and password in production. Really. Now notice that I output two strings: good and bad. Remember how I submitForm named a function to run with the result? Let's look at that now:
2 if(s == "good") {
3 //first hide the window
4 ColdFusion.Window.hide('loginwindow');
5 //rewrite out login
6 var loginspan = document.getElementById('loginstatus');
7 var newcontent = "<a href='index.cfm?logout=1'>Logout</a>";
8 loginspan.innerHTML = newcontent;
9 } else {
10 alert('Your login didn\'t work. Try paris/hilton');
11 }
12}
The function was passed the response, so all I need to do is check the value. If it is good, I hide the window (again, using the ColdFusion/Ajax API. Now I do something fancy. It wouldn't make sense to keep the login link on the page. I wrapped my login link in a span:
This lets me get the span and change the HTML inside. Pretty simple, right?
To see an online demo of this, go here: http://www.coldfusionjedi.com/demos/login/index.cfm
Obviously someone could do this a lot prettier then I did - but notice how nice it works. You can login from any page, and when done, you are still on the page you were looking at. (I do something like this for the contact form at CFBloggers.org.) Also note how little JavaScript was involved. The most complex bit was handling the result of the login, and even that was just about 10 lines of code.
Enjoy. I've attached the code to this blog entry.


Thanks for the great info.
Thanks for all the hard work.
Anyway, I meant thanks for all the hard work generally. I find your blog an invaluable resource. Keep up the good work.
BTW...I think you have a Typo on your "Buy Us" page:
<quote>Our you incredibly rich?</quote>
<grin>
Troy
From Ben: Official line is all current IE, FF, Opera and Safari. Safari has issues with FCK though.
The previous quote is in regard to supported browsers.
For JS turned off - there is no official way to handle stuff.
For my demo - you could easily make the login link go to a traditional form. Look at my blog entry on Spry and HTML Panels and how they handle graceful degradation. That style of link would work just fine here.
Other than that, I suppose it's an issue of 'know your user' which determines how much trouble to go to.
I have found that there are not too many people that disable JavaScript these days. Here are some statistics from the last 30 days on the most popular site I work on:
JavaScript enabled:
Yes - 309,475 visitors - 99.44%
No - 1,756 visitors - 0.56%
And a lot of those people that didn't have JavaScript enabled were people browsing on their blackberry's and such.
But then again, at our current conversion rate and average order value, those 1,756 people per month could represent about $12,000 in sales so that would make it well worth my effort to make sure they could browse my site easily without javascript, even though they should be paying attention to their driving and not shopping online with their phone =)
Maybe I misunderstood the post in that case. I was actually thinking of this example "Tooltips With Interactive Content" towards the bottom of this page:
http://labs.adobe.com/technologies/spry/samples/to...
I imagine that your previous posts on posting data from spry using the "post" method can be combined with that sample and create a similar effect.
Thank you, this is just what I was looking for!
I am not a CF developer, just a big fan. This was very helpful.
If I am going to check this against a database with hashed passwords, where do you propose I add that? To the processlogin.cfm file?
Also, I'd like this to be modal, so that if someone goes to a page they don't have access to, they won't see the content until they log in.
I have two other customization questions.
If the user enters an incorrect user name or password, it leaves the data in the fields. Can you suggest a way to clear the fields after the notice?
Also, can you propose a way to include a "forgot password" link in the login.cfm page that would close the cfwindow and redirect them to the forgot password page?
Many thanks, Cliff
This looks great and appears to be clear as mud until I try to run it in CF8. I have a js alert in begining of my handleResponse function which tells me the value of "s" (either good or bad passed from the processlogin.cfm). Trouble is, although I can see the value is being passed correctly (i.e s=good) it never logs me in as the js function does not seem to be treating "s" as a string...or something?
Any ideas please?
Or are you saying the result of s "looks" to be good, but the stuff in the s=="good" portion isn't running? If so, I'd consider using Firebug and debugging the result. You can use console.log(s) to see the value.
I was tinkering with things and trying to learn more, so I have modified your script so that if the login fails, it runs a cfajaxproxy instance to a cfc to count the number of failed logins and returns the "x failed logins" to the login window and updates a div. This works beautifully, but the code only runs on a form submit event.
So what I was wanting to do was also run the code just after the coldfusion.window.create code as well, but this fails, I think because I would need to run it after some sort of ready event. Is there such a thing available when using the inbuilt coldfusion.window.create function?
I am looking into the FW/1 Framework and was wondering how I might incorporate this into the framework? I can't seem to get the good to return to the function, so I can't log in. Any ideas?
I am really new to frameworks, and from what I have read (on your blog and others), this framework might be the best to use to start understanding frameworks.
thanks for the help
Dan
Does that make sense?
In my views folder I have a login folder with the login.cfm and processlogin.cfm pages. on the default.cfm page I run the cfwindow tag that will pop open the window with the source of the cfwindow tag being: index.cfm?action=login.login.
on the login.cfm page I have my fields for id and pass. I submit using your js call to the function that does the submitForm. I have this and all my javascript calls on my default.cfm page in my layouts folder.
This is where I have my issue. It runs the submitform (i think), and is suppose to call handleResponse js when it is done (this also on the default.cfm page in layout folder). It seems to call the function, however the variable of good is set on the processlogin.cfm page and I don't really know how it can be used in the response js.
I am having a hard time getting my head around controllers, services, layout, etc. and how data passes. Also, I have not done a lot of cfscripting, and alot of the code you all are writing now is in cfscript...it is taking me a while to convert that over in my head.
Anyway, thanks first for blogging about this framework, would not have known about it if not. Also thanks for any help you can give me...
The more example code from anyone using this framework would be great for not only me, but for anyone else that wants to check out FW/1.
Thanks again.
Dan
Thanks for all the information.
[Add Comment] [Subscribe to Comments]