jQuery Does Not Post Undefined Values In AJAX Requests

Posted February 8, 2011 at 10:40 AM by Ben Nadel

Tags: ColdFusion, Javascript / DHTML

NOTE: The original premise of this post was WRONG. I talked about NULL values, but demonstrated "undefined" values. This only applies to Undefined values!! Thanks to Justice for this critical catch!!

When you trigger an AJAX request in jQuery, you have the option to supply a "data" object with the request. This data object contains a collection of key-value pairs that get posted as individual form (or url) parameters. There is a small feature of the AJAX request model that took me a little while to get used to; but, now that I understand it, I completely love to use it. What I'm referring to is the fact that Undefined values are not posted during an AJAX request.

To demonstrate what I'm talking about, take a look at the following jQuery page:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Undfined Values And AJAX Requests</title>
  • <script type="text/javascript" src="../jquery-1.4.4.js"></script>
  • </head>
  • <body>
  •  
  • <h1>
  • Undefined Values And AJAX Requests
  • </h1>
  •  
  • <form>
  •  
  • <input type="submit" value="Post AJAX" />
  •  
  • </form>
  •  
  • <div id="results" style="margin-top: 30px ;">
  • <!--- This is where we'll post the AJAX response. --->
  • </div>
  •  
  •  
  • <!--- ------------------------------------------------- --->
  • <!--- ------------------------------------------------- --->
  •  
  •  
  • <script type="text/javascript">
  •  
  • // Create an object to hold a number of values that we are
  • // going to be posting to the AJAX request handler.
  • var clientSideData = {
  • a: 1,
  • b: 2,
  • z: 3
  • };
  •  
  •  
  • // Now, bind to the form to trap the submission and handle it
  • // via an AJAX request.
  • $( "form" ).submit(
  • function( event ){
  •  
  • // Prevent the default form submission.
  • event.preventDefault();
  •  
  • // Now, post varaibles to the request handler.
  • //
  • // NOTE: As we do this, some of the values we pass
  • // will exist, some will not.
  • $.ajax({
  • type: "post",
  • url: "./handler.cfm",
  • data: {
  • a: clientSideData.a,
  • b: clientSideData.b,
  • c: clientSideData.c,
  • x: clientSideData.x,
  • y: clientSideData.y,
  • z: clientSideData.z
  • },
  • dataType: "html",
  • success: function( html ){
  •  
  • // Dump the response into the page.
  • $( "#results" ).html( html );
  •  
  • }
  • });
  •  
  • }
  • );
  •  
  • </script>
  •  
  • </body>
  • </html>

At the top of my Javascript, you'll notice that I am defining a client-side data structure with a few properties. Then, when I go to trigger my AJAX request, you can see that I am posting both defined (a, b, z) and undefined (c, x, y) properties from said data structure. Now, rather than passing c, x, and y as Undefined values or some sort of empty string or falsey value, jQuery simply ignores them.

To illustrate this, my AJAX request handler - handler.cfm - echoes its own FORM scope:

handler.cfm

  • <!--- Set the response type. --->
  • <cfcontent type="text/html" />
  •  
  • <!---
  • Simply CFDump out the FORM post values so that we show the
  • client which form variables were passed with the AJAX request.
  • --->
  • <cfdump
  • var="#form#"
  • label="Form Post"
  • />

And, when we make the AJAX request, we can clearly see that our undefined values are neither posted to the handler nor echoed back in the response:

 
 
 
 
 
 
UNDEFINED Values Do Not Get Passed Along With A jQuery AJAX Request. 
 
 
 

At first, this might feel weird; after all, if you tell jQuery to post something, shouldn't it at least try to post the Key? Once you get used to this concept, however, it becomes really nice to work with. Take, for example, something like the Javascript Geolocation API. When you work with geolocation and the browser, the user has the opportunity to deny geolocation access; and, even if access is granted, there is a chance that the browser won't be able to determine the proper location.

This means that if you need to post geolocation information back to the server, there's a chance that no location information will be available. You could use some complex client-side logic to dynamically build your AJAX data object based on the information that is available; or, you could just post NULL values and live hassle-free.

  • // Default the location to a undefined coordinate set. This way, we
  • // have a constant data structure.
  • var location = {};
  •  
  •  
  • // -- Get geolocation... code not shown. Will update the
  • // -- the location data struct once latitude and longitude
  • // -- become available.
  •  
  •  
  • // Post location to the server. It may be UNDEFINED.
  • $.ajax({
  • ...
  • data: {
  • latitude: location.latitude,
  • longitude: location.longitude
  • }
  • ...
  • });

Here, you can see that the location information starts off as undefined coordinate values that may or may not be updated over time. Then, when we go to post the location, we simply post the local coordinates, not taking into account whether or not they are defined. We leave the "checking" up to jQuery and allow our client-side code to remain as simple as possible.

I know this is just a tiny feature of the jQuery AJAX request model; but, it is a feature that I have come to really like. And, as your client-side code starts to become more robust, the chances that you'll post Undefined values to the server definitely go up. It's nice to know that jQuery doesn't require us to worry about the insignificant details.




Reader Comments

Feb 8, 2011 at 11:01 AM // reply »
12 Comments

Hey Ben,

What do you use to annotate your screenshots?


Feb 8, 2011 at 11:04 AM // reply »
11,243 Comments

@Anthony,

I just take a screenshot and mark it up in Adobe Fireworks.


Feb 8, 2011 at 11:33 AM // reply »
148 Comments

There's a plugin for Chrome that allows you to do this as well. Here it is:

https://chrome.google.com/extensions/detail/alelhddbbhepgpmgidjdcjakblofbmce


Feb 8, 2011 at 11:35 AM // reply »
148 Comments

Not sure if the Chrome version can do the Console (if that exists for this browser), though.


Feb 8, 2011 at 11:43 AM // reply »
11,243 Comments

@Lola,

In Firefox, I have a great extension called "ScreenGrab!". It allows you take a screen shot not just of the visible screen, but also of the entire web page (below the fold of the window).

For things like this, though, where I need to get the Console in the picture, I just the OS native functionality. On Mac, I'm rocking SHIFT+CTRL+CMD+3 (that's a finger-twister for you!).


Feb 8, 2011 at 12:06 PM // reply »
211 Comments

@Anthony: Ben draws all the pretty pink lines and text himself. ;)


Feb 8, 2011 at 12:33 PM // reply »
113 Comments

@Ben,

Note that in the sample code with screenshot, you did not include *null* values. You included *undefined* values. These are two very different things in JavaScript. In the example of clientSideData.c, c is undefined. What happens if you set clientSideData.c = null (rather than undefined, i.e., setting a value of null to that key rather than never having set any value at all to that key) and then attempt the POST with jQuery?

Cheers,
Justice


Feb 8, 2011 at 12:36 PM // reply »
270 Comments

Hi @Ben.

Did you notice that AJAX was rewritten from the ground up in jQuery 1.5? Since you used 1.4.4 in your experiment above, you might want to download 1.5 and see if its behavior is upward compatible.

We have 1.5, but the behavior above doesn't change how we have to code. Our callbacks are generally to look up a hand-entered Zip code or NAICS code in a text box, for example. In other words, this.form.Zip.value could be the nullstring, which makes it defined, which means we have to code cfif IsDefined ("URL.Zip") and (Len(URL.Zip) gt 0) anyway.

P.S.: Pre-OS-X slang calls Shift-Command-digit utilites FKEYs. The full screen grab is called FKEY 3, for example. You can also (minimally) annotate your screen grabs in Preview. You can also crop in Preview via select, copy, New from Clipboard. In a pinch, these techniques can be used on any OS X Mac, where you can't necessarily control what 3rd party software is installed.


Feb 8, 2011 at 12:40 PM // reply »
11,243 Comments

@Justice,

Hmmm, crap, you're right :( In the middle of a meeting - will clarify afterward. I think I made a big mistake here :)


Feb 8, 2011 at 1:02 PM // reply »
11,243 Comments

@Justice,

You are right, by the way; null values get converted to the string, "null" and undefined values get ignored... still in my meeting, but this makes the post mostly irrelevant.

I swear I thought I have tested this. But, I suppose that I do typically use this with undefined values.

Will update shortly.


Feb 8, 2011 at 1:22 PM // reply »
11,243 Comments

@Todd,

Pink for the win!!

@Justice,

The post has been updated. Your eagle-eye has once again proved immensely valuable. Thanks for getting my back!

@WebManWalking,

Yeah, I typically have to add some sort of server-side check like isNumeric(). I also use CFParam to default values when acceptable.


Feb 8, 2011 at 3:28 PM // reply »
1 Comments

Does this still strictly identical with jQuery 1.5 and its AJAX module rewrited or some changes has been made ?


Feb 8, 2011 at 3:30 PM // reply »
11,243 Comments

@Pomeh,

I have not had a chance to play with jQuery 1.5 just yet. I think the changed made to $.ajax() in 1.5 had more to do with multiple handler assignments and assignment after-the-fact. I am not sure than any core "behavior" has changed.


Feb 8, 2011 at 5:17 PM // reply »
270 Comments

http://blog.jquery.com/2011/01/31/jquery-15-released/


Feb 8, 2011 at 10:54 PM // reply »
11,243 Comments

@WebManWalking,

I'm especially interested in the Deferred stuff. I know very little about that and am curious to see what the buzz is about. In my Seven Languages book, they sometimes talked about things called, Futures, which were results that had not been created yet; but, that kind of stuff was happening at the language level.


Feb 9, 2011 at 12:34 PM // reply »
270 Comments

@Ben,

It's easy to confuse null and undefined if you're a ColdFusion or Java developer. You've already written on that similarity in ColdFusion. Consider also a HashMap in Java:

  • HashMap hm = new HashMap();
  • hm.put("key", "value");
  • ...
  • hm.put("key", null); // Don't need it anymore.
  • ...
  • String getNullOne = hm.get("key");
  • String getNullTwo = hm.get("undefinedkey");

Once the values have been moved out to Strings, how do you distinguish getNullOne from getNullTwo? You don't. They both contain null, getNullOne because that's what got put to it and getNullTwo because the key was never defined.

Of course, you can define an Iterator over hm and discover defined keys that way. Or you can call hm.containsKey(). But after the values are moved out to Strings, they're both null and indistinguishable.

So don't beat yourself up too excessively over null versus undefined. Common problem.


Feb 12, 2011 at 7:15 PM // reply »
54 Comments

I didn't find this problem. It's probably only related to POST requests. I will check further when I have a server to see if things came through.

var data = {
a: 1,
b: 2};
jQuery.ajax({
url:'http://www.bennadel.com/',
type: 'post',
dataType: "html",
data:{
a: data.a,
b: data.b,
c: data.c
}
});
---Firebug output---
Parametersapplication/x-www-form-urlencoded
a 1
b 2
c undefined
Source
a=1&b=2&c=undefined

jQuery version 1.3.1 (firebug on your site)


Feb 17, 2011 at 10:39 AM // reply »
11,243 Comments

@WebManWalking,

I appreciate the support - I feel like I was just being sloppy :) It's ok though, onward and upward!

@Drew,

On my testing server, I am getting the same behavior (undefined not passed) using either the GET or POST approaches. But, this blog was probably tested in jQuery 1.4.x and the local testing I just did was on jQuery 1.5. Perhaps it was a behavior they added later on?


Feb 17, 2011 at 10:51 AM // reply »
54 Comments

@Ben, I checked on jsFiddle. This started after 1.3.2, this behavior occurred in 1.4.2 and 1.4.4. I'm going through their changelog/bugs and see if this is intended behavior or a regression.


Feb 17, 2011 at 10:54 AM // reply »
11,243 Comments

@Drew,

Nice detective work, and excellent use case for jsFiddle! I have to believe that this is the intended behavior; I can't think of a reason why an "undefined" value would want to get passed through.


Feb 17, 2011 at 11:16 AM // reply »
54 Comments

//This is totally false, strict JSON parsing is on the return not the request. I have no idea why this changed in 1.4. https://github.com/jquery/jquery/commits/1.4/src/ajax.js

@Ben, I think it boils down to their switch to using 'proper' JSON parsing. "{"a":1,"b":undefined}" must not be valid JSON.

In order to avoid reading the entire spec (because I want to go running before lunch), I made this simple test to prove my hypothesis:

[Console]
var data = {a: 1, b: undefined};
JSON.stringify(data); //"{"a":1}"

Of course, only a subset of browsers support JSON.stringify. TBH, I don't see where jQuery stringifys (which it doesn't provide direct support for, because of these reasons http://bugs.jquery.com/ticket/5947).

I would like to see how IE6/7 work with this same type of request. Anyways, the $.ajax demo is available here: http://jsfiddle.net/xEym4/

You are right, I don't believe this is a bug and a very good thing to know. Thanks!


Feb 18, 2011 at 9:38 AM // reply »
11,243 Comments

@Drew,

I just hope that it is working the same way across browsers, given then same version of jQuery. I thought maybe it had to do with the iteration over the object; but, you can check for keys with undefined values and they do exist.


Feb 27, 2012 at 2:10 PM // reply »
369 Comments

@Ben,

I wanted to thank you so much for this! I was having a little problem with my jquery I had written, and I did a search on Google. Your blog popped up about the 5th or 6th answer down. Because they were above yours, I checked the others first before even realizing it was your blog. Your blog was the only one out of the list that helped me. (and that was actually my second search for this) It really helped a lot. Thanks so much!!! You are such a huge help to me when I have problems pop up with my coding, both big and small. This was a problem I had been spending quite a bit of time trying to solve. Your solution here helped me so much...and I am writing using php with jquery and not ColdFusion! Yet it still helped immensely. Thank you so much! Do you know if you happen to have a blog related to a loading gif for when jquery is doing work with the database so users understand that something is going on and happening behind the scenes and don't go crazy with your app? Just thought I'd ask. But anyway, regardless...thanks so much for all of the help I've already gotten from you.


Feb 27, 2012 at 2:12 PM // reply »
369 Comments

*of course, I meant do you know if you have a blog post for that...I wouldn't expect you to have an entire blog dedicated solely to that. Just wanted to clarify. :-D



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
May 23, 2013 at 5:19 AM
Ask Ben: Print Part Of A Web Page With jQuery
How to print also the background color of table cells and table lines ... read »
May 23, 2013 at 3:55 AM
Javascript Array Methods: Unshift(), Shift(), Push(), And Pop()
very interesting and helpful too. ... read »
May 22, 2013 at 5:35 PM
Script Tags, jQuery, And Html(), Text() And Contents()
This is still an issue 2 years later. jQuery is supposed to remediate these cross browser issues, no? I have been unable to find any statement from the jQuery team calling this behavior "by de ... read »
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
May 22, 2013 at 12:29 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben: What version of Java are you using? Also, did you test users.id to see what Java reports as the data type? I wonder if it's not a Java primitive data type, but getting returned as something ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools