Ajax Programming Common Errors

Friday, July 18, 2008

You might already know about it, but I think It's still worth mentioning, the common issue some developers stumble on:

1. GET Requests Caching on Browsers
Sometimes, when making repeated GET XMLHttpRequest to the same uRL can lead to the response coming from the browser cache and not from the server. Especially when you're using Internet Explorer. And this IS annoying.

With no-cache or similar HTTP headers, this problem can be solved, theoritically, but in a real life coding this cache is sure difficult to get rid off.

The most effective way to solve this problem is add an always update or random variable to the URL where the request is sent. So the browsers read this request as a different page request and returns the server page rather than the cached version.

So, if usually we send a request like this
var url="somescript.php?var1="+var1; XMLHttp.open("GET", url);
Now we just simply add a random varible like this
var url="somescript.php?var1="+var1+"&rand="+new Date().getTime(); XMLHttp.open("GET", url, true);


2. Escaping Variables
Remember, when creating GET or POST requests, you must escape every variables that have possibility to contain nontext characters or spaces. It's a good way to avoid crafted variables by people who like to mess or just test your codes. It goes simply like this:
XMLHttp.open("GET", url+escape(var1)+"?rand="+new Date().getTime(), true)

3. Permission Denied
Usually means that you have cross-domain scripting requests happen. Like what I've wrote earlier, an XMLHttpRequest object can't be made across different domains by default due to security matter. So by default, calls must be made to server scripts existing in the same domain as the calling scripts. And please notice that domain must be written EXACTLY in the same way, mydomain.com may be interpreted as different domain from www.mydomain.com, thus, permission will be denied. Here and here, you can find out how to solve this cross-domain issue.

Cross Domain Scripting with AJAX, Again

Thursday, July 17, 2008

I've wrote about how to overcome the cross-domain issue using Apache mod_rewrite. But that'll only work if you have administrator priviledge on your hosting server, most of us don't. So instead of tweaking the server we must tweak the code. Thus, JSON shows up.

JSON(JavaScript Object Notation) is just a way to structure object data.. in a way that is easily interpreted, primarily with Javascript. Some examples from wikipedia:
Javascript

bork({"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}});

and with different format:
XML :
<menu id="file" value="File">
  <popup>
    <menuitem value="New" onclick="CreateNewDoc()" />
    <menuitem value="Open" onclick="OpenDoc()" />
    <menuitem value="Close" onclick="CloseDoc()" />
  </popup>
</menu> 

Aha, so just like xML, JSON is just data representation part of things, but if XML can't handle cross-domain scripting, how can JSON ?

It's because the J letter on JSON, JSON is JavaScript. And we all(well, maybe not all) know that you can reference REMOTE Javascript source inside the <script> tag. So theoritically, if you create a dynamic script tag that references to a script on another domain, that script is executed imediately!. And if the remote script contains JSON, your cross-domain scripting problems days are over!. Yay.

For an even easier way, you can use a js file at Dan Theurer's blog for the dynamic adding of scripts elements.

And here's how you use it.

First, a server side file that creates the JSON outputs, named bork.php
<?php
 echo 'bork({"Image": { "Width":500, "Height":250, "Title":"Giant Cow", 
         "Thumbnail":{"Url":"http://someurl.com/image/1234", 
         "Height": 75, "Width": 150}}});';
?>


And the html file ,bork.html
<html>
<head>
<title>JSON test</title>
<script src="jsr_class.js" type="text/javascript"></script>
<script>
function appendScript(){
 var json=new JSONscriptRequest('http://myotherdomain.com/bork.php?');
 json.buildScriptTag();
 json.addscriptTag();
}

function bork(data){
 var txt='';
 if(data==null)
  alert('error occured');
 else{
  txt='Image Title: '+data.Image.Title+'
'; txt+='Width: '+data.Image.Width+'
'; txt+='Height: '+data.Image.Height+'
'; txt+='Thumbnail Data: '+data.Image.Thumbnail.Url; txt+='('+data.Image.Thumbnail.Width+' x '+data.Image.Thumbnail.Height +')
'; } document.getElementById('bork').innerHTML=txt; } </script> </head> <body> <div id="bork"></div> <a href="#" onClick="appendScript();return false;">Get Bork</a> </body> </html>

Hope this helps.

Printer-Friendly Page With CSS

Monday, July 7, 2008

Ok, so you want to create a printer-friendly page without having to create another web page for that purpose. Here's how.

First, create a separate stylesheet with the rules for the page to be printed. Usually, this css is named print.css, so maybe you should name your it print.css too :D.

Second, link the stylesheet to the page and set the media property to print.
<link rel="stylesheet" type="text/css" href="base.css" media="screen" /> <link rel="stylesheet" type="text/css" href="print.css" media="print" />

You see, the default value for the media attribute is all, so if you don't specify the attribute the browser will apply the CSS rules to all media. There are actually ten media types:

Media Type Description
all Suitable for all devices
braille For Braille tactile feedback devices
embossed For paged Braille printers
handheld For handheld devices
print For paged material, documents viewed on-screen in print preview mode
projection For projected presentation, i.e projectors
screen Primarily for color computers screens
speech For speech synthesizers
tty For media using fixed-pitch character grid i.e teletypes, terminals, or devices with limited display capabilities
tv For television-type devices


If you want to define the stylesheet for several media, separate the media values with comma, like this
<link rel="stylesheet" type="text/css" href="dual.css" media="print, projection" />

And beside using link method, you can also use import, like the following line @import URI(dual.css) print,projection; And stil there's way to define stylesheet and media types, it's by using the @media, which enables writing css rules that can be set for different media, all in one stylesheet
<style type="text/css">
@media print{
 #container {
  font-size: 10pt;
  background: #FFFFFF;
  color: #000000 
 }
}

@media screen{
 #container {
  font-size: .8em;
  background: #0000FF;
  color: #FFFFFF 
 } 
}
</style>


Hope this helps.