During the last several weeks I have been making considerable progress in using Appcelerator Titanium. The new KnowledgeTree client application in Titanium, which I am working on at work, is coming along nicely.

Using Javascript in Titanium is easy, although one thing that is lacking at this stage are tutorials and sample code for the Titanium-specific extensions are not easy to come by, and the forums are still too new to have answers to everything, so at times, this means prodding around in the dark trying to get things to work.

As a result of this, I thought it would be a good idea to write up some of the lessons I have learned from using Titanium so that I can share them with the world.

Just this morning, I managed to crack an issue I have been struggling with for a few days: How on upload a file to a webserver using Javascript.

One of the ways to accomplish this is to use the XMLHttpRequest object to upload a file using a form post. However, Titanium has wrapped this functionality in the HTTPClient object.

To instantiate a new instance of this object, all you need to do is:

    var xhr = Titanium.Network.createHTTPClient();

This creates a new HTTPClient object which can now be used. The next step is to create the content that we are going to send to the HTTPClient. The content will take the form of a MIME multipart message. So to create the headers for the file upload:

   var boundary = '----12345568790';
   var header =  "--" + boundary + "\r\n" + "Content-Disposition: form-data;
         name=\"var1\"\r\n\r\n" + var1 + "\r\n";
   header += "--" + boundary + "\r\n" + "Content-Disposition: form-data;
         name=\"var2\"\r\n\r\n" + var2 + "\r\n";
   header += "--" + boundary + "\r\n" + "Content-Disposition: form-data;
         name=\"var3\"\r\n\r\n" + var3 + "\r\n";
   header += "--" + boundary + "\r\n";
   header += "Content-Disposition: form-data; name=\"" + name + "\";";
   header += "filename=\"" + filename + "\"\r\n";";
   header += "Content-Type: application/octet-stream\r\n\r\n";

What this code does is builds the header, where var1, var2 and var3 are arbitrary values which you would like to pass to the server, which could be anything, such as a session id to identify which session the file is attached to to, etc. the filename value is the name of the file we are going to upload.

The boundary value must start with ‘–’ and the number portion can be generated so each request would have a different value, although within the same request the boundary value must remain the same.

The last line in the above code tells the server to expect binary data to follow.

The next step now is to read the contents of the file we want to read and add it to our header text

   var userDir = Titanium.Filesystem.getUserDirectory();
   var uploadFile = Titanium.Filesystem.getFile(userDir, 'test.txt');
   var uploadStream = Titanium.Filesystem.getFileStream(uploadFile);

   uploadStream.open(Titanium.Filesystem.FILESTREAM_MODE_READ);
   content = uploadStream.read();
   uploadStream.close();

   var fullContent = header + content + "\r\n--" + boundary + "--";

Now that we have the contents we would like to post, we then set up the HttpClient object like this:

   xhr.open("POST",url);
   xhr.setRequestHeader("Content-type", "multipart/form-data;
           boundary=\"" + boundary + "\"");
   xhr.setRequestHeader("Connection", "close");
   xhr.send(fullContent);

The methods here are very similar to the XMLHttpRequest object’s methods, however, when using the XmlHttpRequest object, the length of contents needs to be specified. the HttpClient object calculates the contents size automatically and therefore it is not needed to be explicitly specified.

One line which is important is the second last line which sets the “Connection” header to “close”, since in my experiences with the object, the server won’t be able to recognize that the entire file has been sent without expliciting setting “Connection” to “close”.

After the xhr.send() method call, the file is now on the way to server, where the upload can be processed by a script on the server. In my case, I have a php script which processes the upload and then returns the results back.

To check on the results returned (if any) we can use the onreadystatechange event

   xhr.onreadystatechange = function(){
      if (this.readyState == 4){
         alert(this.responseText);
      }
   }

That is all there is to uploading files using Titanium.

There are other ways of uploading files, for example there is a sendFile (data) method, in the HttpClient object, but I have not yet managed to get that working the way in which I need it to.

For more information, and a full listing of methods, you can refer to the Titanium API documentation

Share