Someone in #flex was talking about how there were no good examples for doing uploads with Flex and ColdFusion. Sounded like an excellent topic to cover here. Now this example is a tiny bit more complex than previous examples, because I needed to cover two methods of functionality: single file uploads and multi-file uploads. Both processes are very similar, and in my code they actually share a method.
Here’s the MXML application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" layout="absolute"> <mx:Script> <![CDATA[ import mx.controls.Alert; private var myFileList:FileReferenceList; private var myFile:FileReference; private var uploadTarget:URLRequest = new URLRequest("upload.cfm"); private function init():void { myFileList = new FileReferenceList(); myFileList.addEventListener(Event.SELECT,fileListSelected); myFile = new FileReference(); myFile.addEventListener(Event.SELECT,fileSelected); } private function fileListBrowse():void { // we only want to allow images to be uploaded var imagesFilter:FileFilter = new FileFilter("Images", "*.jpg;*.jpeg"); myFileList.browse([imagesFilter]); } private function fileBrowse():void { // we only want to allow images to be uploaded var imagesFilter:FileFilter = new FileFilter("Images", "*.jpg;*.jpeg"); myFile.browse([imagesFilter]); } private function fileListSelected(e:Event):void { // here we could do whatever we want, but we're just going to // upload right away uploadFromList(); } private function fileSelected(e:Event):void { // here we could do whatever we want, but we're just going to // upload right away uploadFile(myFile); } private function uploadFromList():void { if (myFileList.fileList.length > 0) { // if there are still files left to upload, continue myFile = myFileList.fileList[0] as FileReference; uploadFile(myFile); } else { // if there are no more files, stop return; } } // NOTE: this method is used for one or multiple files private function uploadFile(f:FileReference):void { // here we build out the other form items var urlVars:URLVariables = new URLVariables(); urlVars.myFirstValue = 1; urlVars.myOtherValue = "something else"; // add the form items to the request uploadTarget.data = urlVars; // set request the method to POST uploadTarget.method = URLRequestMethod.POST; // add the event listeners // DataEvent.UPLOAD_COMPLETE_DATA only fires if data is returned and the flash player supports it // otherwise, use Event.COMPLETE f.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,onDataComplete); f.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); f.addEventListener(ProgressEvent.PROGRESS, progressHandler); // show the progress bar myProgress.visible = true; // start the upload f.upload(uploadTarget,"myUploadFieldName"); } private function ioErrorHandler(e:IOError):void { // there was some error, you'll want to tell someone Alert.show("Error occured, oops!","I/O Error"); } private function progressHandler(e:ProgressEvent):void { // update the ProgressBar myProgress.setProgress(e.bytesLoaded,e.bytesTotal); } private function onDataComplete(e:DataEvent):void { // here we could handle whatever was returned by the server. XML is probably your best bet. // var myResult:XML = XML(e.data); // would work for XML var myResult:String = e.data; // if there were multiple files, delete the one we uploaded and try another if (myFileList.fileList.length > 1) { // remove what we just uploaded myFileList.fileList.splice(0,1); // go upload another another uploadFromList(); } else { // if this was the last of a multiple file upload, remove it if (myFileList.fileList.length > 0) { myFileList.fileList.splice(0,1); } // we're done uploading myProgress.visible = false; return; } } ]]> </mx:Script> <mx:VBox height="100%" width="100%" horizontalAlign="center" verticalAlign="middle"> <mx:Button label="Choose One File to Upload..." click="fileBrowse()"/> <mx:Button label="Choose Multiple Files to Upload..." click="fileListBrowse()"/> <mx:ProgressBar id="myProgress" mode="manual" label="Uploading" visible="false"/> </mx:VBox> </mx:Application> |
The comments point out all the nuances you need to know about. It does the major features, including passing more data with the file, what you can do with the progress event, how to do an upload queue, rather than uploading all selected files at the same time, and how to handle responses from the upload script. This code will work with any backend processor, not just ColdFusion.
Here’s the ColdFusion file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <cfsetting enablecfoutputonly="true"> <!--- this will upload the file ---> <cffile action="upload" fileField = "myUploadFieldName" destination="#expandPath("./")#uploads/"> <!--- note that all formfields including FORM.myFirstValue and FORM.myOtherValue ---> <cfscript> myVal1 = FORM.myFirstValue; myVal2 = FORM.myOtherValue; </cfscript> <!--- here you can send stuff back to flex, only if the flash player is 9.0.28.0 or later ---> <cfoutput><myXML> <file uploadedAs="#cffile.serverFile#"> </myXML></cfoutput> |
It doesn’t do much, but you can see how to get non-file data passed from flex, and how to send a response. Make sure that, when sending a response, you don’t send any whitespace before what you intend to send back to Flex. Also, note that your users need the Flash Player version 9.0.28.0 or later in order to send responses back to flex.