Uploading a file and not reloading the page
Today I was tasked with a seemingly simple situation:
Create an upload button within a form, submit to the page without reloading, and display the new entry.
AJAX was the first thing to come to mind. However.. it didn’t work. I ended up having to create a hidden iFrame, adjust my form target, and retrieve the result.
Let’s look at some code tidbits.
var iframe;
try {
//O I hate IE ><
iframe = document.createElement('<iframe name="uploadFrame"></iframe>');
} catch (ex) {
iframe = document.createElement('iframe');
iframe.name = 'uploadFrame';
}
var initAction = document.getElementById('skillsForm').action;
iframe.id = 'uploadFrame';
iframe.style.display = 'none';
document.body.appendChild(iframe);
document.getElementById('skillsForm').target = 'uploadFrame';
document.getElementById('skillsForm').action = webPath + '/skills/_uploadDoc.cfm';
document.getElementById('skillsForm').submit();
document.getElementById('skillsForm').target = '';
document.getElementById('skillsForm').action = initAction;
What’s going on?
I created an IFrame, got the default action (it was different than my new action), appended the iframe to the body (which this really doesn’t matter where it is appended to), and manipulated the target. This sent my form off to the correct page and processed it.
To get the result, I used a little Jquery magic =):
var fileName = '';
$('#uploadFrame').load( function(){
fileName = $('#uploadFrame').contents().find('#docFileName').html();
...
});
Of which this found the element with the id of docFileName and returned to me the text.
Setting up PHP 5 on IIS 5
This was tons of fun, in a few easy steps:
**NOTE: I am installing using CGI and not ISAPI
- Download and unzip PHP package to desired PHP directory (eg: C:\PHP)
- Add ‘;c:\PHP’ (or wherever you stored your PHP directory without quotes) to your PC Path. To get there go to “my computer” -> right click > properties > advanced > environement variables > and add to the system variable ‘Path’
- Restart your computer
- Open IIS
- Right click on your site or virtual directory
- Make sure execute permissions on the home tab says ’scripts only’
- Click configuration and click add to add the PHP executable
- Add ‘.php’ as the extension and browse to your php folder and add php-cgi.exe as the executable
- Leave everything else the same and click okay a few times…
- Go back up from your home directory and click on web service extension. It is the same level as your website branch.
- Right click and go to “add new web service extension”
- Type PHP as the name and browse to php-cgi.exe for the required file.
- Create and test a PHP file!
Coldfusion & Cfouput Group
I really do like Coldfusion. No, really =).
However, here is an ever so useful tip brought to you by me – CodeStar.
So, CFoutput should be on the forefront of every beginner ColdFusion scrip-tor. However, lo- and behold, I wanted to group my results. Simple right? No, not so much. In order to use the group attribute on the cfoutput tag, you must use order by… or else group won’t work. Ah, the joys and wonders of ColdFusion. Of course although I overlooked this, it is documented in the docs:
Use if you retrieved a record set ordered on one or more a query columns.
Javascript OOP, event handling, and THIS!
So today as I was oh so joyfully finishing up a project, I ran into another fun (but enlightening) Javascript issue.
I have an object, and within that object… I have methods (nothing special there, huh?). So, I figured that since all of this is so prettily encapsulated, I should have no issues adding an event handler inside my object that would allow me to click and go to a method inside my object.
Woe is me. You see, the ‘this’ keyword refers to the parent of the caller. And since I changed the caller from my object to my delightful event handler method, this went to the object that called the event, and not the parent object.
So my problem was – how do I access all of my properties and other events that are in my parent object, from my method that was actually an input object… phew.
It did take some work, and some browsing of the Interwebs. Unfortunately, the Interwebs yielded unhelpful and verbose ways to get around what seemed like a simple problem.
I did eventually come across an answer, and here it is – short, sweet, and to the point (unlike me :p).
var objCopy = this;
this.myObjMethod.onclick = function(e) {
objCopy.displayTimes(e);
};
I’m not smart enough to parse Int(’s)
Oye,
So… I was creating a timepicker like that of Google’s calendar app for a client and lo and behold I ran into a fun yet hard to figure out Javascript problem.
Like a good little girl, I was using parseInt on my integers to ensure it was a proper integer. In this case, I was attempting to grab the value that the user inputs as minutes (eg: x:(xx)) and convert that to an integer. Once I had this integer I would use it to create the time increments for the from time text box. This all worked fine and dandy until I came across :08 and :09 .
After much grief and debugging (thank you Firebug!), I finally figured out that it was indeed parseInt as the culprit. The problem? Javascript sets numbers that start at 0 as octal numbers ( more info: http://www.javascripter.net/faq/octalsan.htm ). And guess what? 08 ad 09 are not octal numbers. So… my parseInt function was doing all that I asked it to do – and ended up converting 08 and 09 to 0.
Two points to parseInt, parseInt(09) to me =(. I ended up changing it from a base 8 to a base 10 – which of course gave me my 08 and 09.
Conclusion - always add the base to Javascripts parseInt. Unless of course you want octal or you won’t be using numbers with leading zeros.
I love you ColdFusion, I love you not
Okay, so yesterday I was attempting to finish a lovely page where an administrator can edit emails. I wanted to send the form variables in on submit, but since there are hidden forms due to java script displaying each one separately, I wanted the submit to function with AJAX. This worked fine and dandy until I got the great idea of making it even better by using CFtextarea and FCKeditor which it comes with. Upon using this, I found (to my dismay) that ColdFusion renamed the ID element. So no longer could I use getElementById to get my form field value, and CFAjaxProxy’s setForm function wasn’t working to nicely either.
My first idea was to use the “name” of the form field – even though it was generated dynamically. That was alot_of_fun 0.o. It ended up working, however when I would click on submit, it would send in the old value (seemingly cached somehow) and then send in the new one on a second click. This, of course, was not what I desired. So, in the end I found and now use the ColdFusion Ajax Javascript functions – which was as simple as :
ColdFusion.getElementValue(elementId [, formId, attributeName])
Perhaps they should have placed this on the CFTextarea page as a reference of how to get the field value?
Testing a created firefox extension – it’s not showing up!
As I was so merrily going through the Mozilla documentation for creating a plugin here: https://developer.mozilla.org/en/Building_an_Extension, I was dumbfounded when I followed the directions, and didn’t see the “Hello, World” in my status bar. Why oh why Windows are you doing this to me? Well, I found that it was of course, by my own error. When creating the test file in your extensions folder to point back to your extension, make sure that it has no file extension. This means, even when you create the file with your id (eg example@example.com), make sure the file is exactly example@example.com and not example@example.com.txt . Funny how something so small can have you going crazy for hours.
Posting a tweet to Twitter from Coldfusion
Posting a tweet couldn’t be any easier! In PHP you would use CURL to accomplish the same thing.
<cfhttp url="http://twitter.com/statuses/update.xml" method="post"
resolveurl="yes"
username="#username#"
password="#password#">
<cfhttpparam type="url" name="status" value="My API
Tweet!">
</cfhttp>
What’s going on?
Using the Twitter API documentation located here: http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses%C2%A0update, you send in your username and password to the API URL. In this case, http://twitter.com/statuses/update.xml . After that to send in the actual tweet content, you would use cfhttpparam.
What are the limitations?
According to : http://help.twitter.com/forums/10711/entries/15364 , you can post:
# 1,000 total updates per day, on any and all devices (web, mobile web, phone, API, etc. )
# 1,000 total direct messages per day, on any and all devices
# 100 API requests per hour
Also…
Twitter will ignore attempts to perform a duplicate update. With each update attempt, the application compares the update text with the authenticating user’s last successful update, and ignores any attempts that would result in duplication. Therefore, a user cannot submit the same status twice in a row. The status element in the response will return the id from the previously successful update if a duplicate has been silently ignored.
Either way, it’s pretty kewl =).
Server side validating fields
As many of us know by now, it is never best to only validate fields with client side code. You must also validate on the server.
As I was writing code today for a multi-page form, I was trying to think of the best way to validate fields. Although the below is verbose and written in ColdFusion, it can be easily ported to any other language that supports arrays, lists, or hashes – and it can be placed in one line if your language supports associative arrays.
Required fields
For this one I used:
<cfset requiredFields = StructNew()>
<cfset requiredFields['name'] = 'Name'>
<cfset requiredFields['email'] = 'Email address'>
<cfset requiredFields['message'] = 'Message'>
<cfloop collection="#requiredFields#" item="i">
<cfif NOT StructKeyExists(form, i) OR form[i] EQ ''>
<cfset session.errors[i] = 'Field <strong>"' & requiredFields[i] & '"</strong> cannot
be empty.'>
</cfif>
</cfloop>
In this case, the form variable is the name of the form field itself :
requiredFields['email'] = <input type="text" name="email" />
The value of that field is a more friendly name to display with the error messages.
Field Name cannot be empty.
The same type of structures are then setup for numbers, dates, emails, and whatever else may need to be validated. Each loop entry is added to the session.errors array to maintain the errors and then cleared upon re-calling the validation page.
The sessions array is displayed with:
<cfif NOT StructIsEmpty(session.errors)>
<style type="text/css">
li{margin-left:10px}
</style>
<ul class="errorBox">
<cfloop collection="#session.errors#" item="i">
<cfoutput><li>#session.errors[i]#</li></cfoutput>
</cfloop>
</ul>
</cfif>
Creating a list displaying the errors.
**Additionally, to make it an even better experience, you can add an error highlight color to the row that caused the error. For example:
<td style="background-color:<cfif StructKeyExists(session.errors, 'name')>errorRow"><input type="text" name="name" /></td>
** If all of your fields are required, you can simply loop over the form fields and popuplate your errors array… but you may not have the friendly names.
So, why should you validate with server side code?
While client side code such as Javascript makes the user experience much more enjoyable, there are several reasons to also validate on the server.
- Checking on the server can be more verbose and accurate, especially if you need to check against a query (although AJAX would do this as well)
- Javascript can easily be turned off
- YOUR Javascript code can be hacked since it is visible there on the page.
- Your page can be copied completely, javascript removed, and submitted to the server.
- Your Javascript may not work across all browsers and mobile devices.
- Some coders make code inaccessible when they do not make sure the code works without Javascript
So why should you even use it?
- It prevents a trip to the server
- Your users will love you since things will work faster
- You can do muchos with AJAX
Simple JQuery check-all
Simple check all with Jquery:
function checkAll(el, fieldName){
var checkBoxes = $('input[name=' + fieldName + ']');
var curValue = el.value;
if(curValue == 'Check All'){
$.each(checkBoxes, function() {this.checked = true});
el.value = 'Uncheck All';
} else {
$.each(checkBoxes, function() {this.checked = false});
el.value = 'Check All';
}
}
How to use?
Pass in the “this” keyword as the first parameter. Second, pass in the name of the fields that contain the checkboxes. This works only if you set your check all button’s value to ‘Check All’ (ways around this of course).
What’s going on?
Jquery gets all of the elements on the page that are input and have the name attribute equal to the name you passed in. The if conditional checks to see if the value of the first parameter is equal to ‘Check All’. If it is, we iterate over each checkbox and set it to true. We then change the value to ‘uncheck all’. If the value of the first parameter is equal to ‘uncheck all’ we set each checkbox to false, and reset the value to ‘check all’.