Thursday, February 25, 2010

How to Upload Files in CouchApp

‹prev | My Chain | next›

Yesterday I failed to get images to upload as CouchDB document attachments using couchapp. This should be do-able given that the Futon administration interface can do it. Just how easy it is remains to be seen...

...which turns out to be fairly easy!

I borrow code from two of CouchDB's javascript libraries:
  • futon.browse.js—defines how the Futon interface submits its file upload form
  • jquery.dialog.js—attaches actions to futon dialogs like the one that uploads files
What I end up with is this in my upload.html template:
<script src="/_utils/script/json2.js"></script>
<script src="/_utils/script/jquery.js?1.2.6"></script>
<script src="/_utils/script/jquery.couch.js?0.8.0"></script>
<script src="/_utils/script/jquery.form.js?0.9.0"></script>
<script src="<%= asset_path %>/vendor/couchapp/jquery.couchapp.js"></script>
<script type="text/javascript" charset="utf-8">
$("#recipe-upload").submit(function(e) { // invoke callback on submit
e.preventDefault();
var data = {};
$.each($("form :input").serializeArray(), function(i, field) {
data[field.name] = field.value;
});
$("form :file").each(function() {
data[this.name] = this.value; // file inputs need special handling
});

if (!data._attachments || data._attachments.length == 0) {
alert("Please select a file to upload.");
return;
}

$(this).ajaxSubmit({
url: "/<%= dbname %>/<%= docid %>",
success: function(resp) {
$('#saved').fadeIn().animate({ opacity: 1.0 },3000).fadeOut();
}
});
});
</script>
Piece by piece, this function disables normal form submission so that ajaxSubmit() can be used instead:
  e.preventDefault();
Next it assembles all of the data in the form into a Javascript object:
  var data = {};
$.each($("form :input").serializeArray(), function(i, field) {
data[field.name] = field.value;
});
$("form :file").each(function() {
data[this.name] = this.value; // file inputs need special handling
});
After checking to see if the data has an empty file upload field, it performs an ajaxSubmit using the current DB and document ID (as supplied by the show function) and defines a simple on-success callback function:
  $(this).ajaxSubmit({
url: "/<%= dbname %>/<%= docid %>",
success: function(resp) {
$('#saved').fadeIn().animate({ opacity: 1.0 },3000).fadeOut();
}
});
To test this out, I create an empty "test" document (more precisely I use this document from yesterday):



Then, I access the upload show function for the test document (http://localhost:5984/eee/_design/relax/_show/upload/test) and upload my favorite avatar image:



The "Saved" animation shows, which leads me to believe that the image has been successfully uploaded. To make sure, I check the document again:



Sure enough, the image is now attached to the CouchDB test document. Yay!

There is still some more that I would do if I wanted this to be ready for every day use—links back to the main edit page, an automatic redirect after upload, etc.—but that is good enough for today. I am just happy to know that it is possible with relatively little effort.

Day #25

1 comments:

  1. Small addition to a truly purposefull and informative blog entry. This tells the user that the update has failed- firebug console message of success and fail
    (these messages are within pre tags which are not allowed in your blog comments)

    {"ok":true,"id":"test","rev":"25-1223e10f2bd556a67665bc9a0ebae738"}

    {"error":"conflict","reason":"Document update conflict."}



    $(this).ajaxSubmit({
    url: "/<%= dbname %>/<%= docid %>",
    success: function(resp) {
    if(resp.match("ok")){ $('#saved').fadeIn().animate({ opacity: 1.0 },3000).fadeOut();}
    else if(resp.match("error")){ $('#failed').fadeIn().animate({ opacity: 1.0 },3000).fadeOut();}
    }

    ReplyDelete