Add attachment without form node

5746
11
Jump to solution
09-02-2014 11:58 AM
IsaiahAguilera
Occasional Contributor II

I have a mobile phonegap application that has access to the devices camera.  I am trying to take a photo and use the addAttachments method to upload the selected captured image.  My problem is this method only allows for a input type file as the source.  Unfortunately phonegap does not support input file types and I have to upload the captured image directly.  Is there a way to add attachments without using the form type input.  Any help would be greatly appreciated.

0 Kudos
1 Solution

Accepted Solutions
JohnGrayson
Esri Regular Contributor

Actually, a jsfiddle might not be appropriate for this use case.  Below is some code that may work:

var imageName = "someImageFilename";

var imageFormat = "png";

var arrayBufferView = new Uint8Array(imageAsArrayBuffer);

var blobImg = new Blob([ arrayBufferView ], { type: "image/" + imageFormat });

var formNode = put("form", {

  "method": "post",

  "enctype": "multipart/form-data"

});

var formData = new FormData(formNode);

formData.append("attachment", blobImg, imageName+"."+imageFormat));

esriRequest({

  url: "http://[server]/[instance]/rest/services/[folder]/[name]/FeatureServer/[layerid]/[oid]/addAttachment",

  form: formData,

  content: { f: "json" },

  handleAs: "json"

}).then(lang.hitch(this, function(response){

  alert("Attachment Success: " +response.addAttachmentResponse.success)

}), lang.hitch(this, function(error){

  console.warn(error);

}));

View solution in original post

11 Replies
DougCarroll
Esri Contributor

Hi Isaiah,  You are 100% correct the ArcGIS API for JavaScript requires a form node to achieve adding attachments.  It sounds like you may be implementing something like Phone Gap.  Since I am not all that knowledgeable with Phone Gap what could we do different?

Thinking more about this you may just want to set up a related table (not enable attachments).  Then upload items to ArcGIS Online using addItem and then store off the item id or item url into the related table.  Please if you have time, share recommendations regarding how you would want addAttachment to work or how it could be different.

-Doug

0 Kudos
IsaiahAguilera
Occasional Contributor II

Doug,

Thanks for your reply. Yes I am using Phone Gap to build this application.  The issue with Phone Gap is that it does not support input file type.  It relies on its plugins to access the file system and camera.  This wouldn't be an issue except for the addAttachments only taking a form node.  One possible solution that comes to mind is creating a second method that works similar to the old Flex API's addAttachment.  This would allow you to send a base64-encoded string as the argument and would then get encoded to an image.  Or just simply allow the addAttachments method to accept a direct URL to an image file.  Both of these would allow for a more versatile and universally useful addAttachments method.

Unfortunately because of other applications we have set up for viewing these attachments I would not be able to use your suggestion of using related tables. I do however appreciate the help.  Is there any other work around you can think of that I could use to add an attachment. Like I mentioned earlier I can either produce a base64-encoded string of the image or I can access the image directly I just cannot use the input file type.

Thanks,

Isaiah Aguilera

0 Kudos
JohnGrayson
Esri Regular Contributor

Isaiah,  depending on how you get the 'image' we might be able to do this. 

  • create Blob form image
    • type = "image/png" - use correct type here based on image...
    • Can you get an array buffer from image?
    • I have not tried base64 but maybe it will work...
  • create 'form' html dom node
    • method = post
    • enctype = multipart/form-data
  • create FormData using 'form' from previous step
  • append Blob to FormData
    • use 'attachment' as the name
  • call 'addAttachment' REST endpoint of feature

  

If you setup a small jsfiddle with a test service we might be able to try some of this out...

0 Kudos
JohnGrayson
Esri Regular Contributor

Actually, a jsfiddle might not be appropriate for this use case.  Below is some code that may work:

var imageName = "someImageFilename";

var imageFormat = "png";

var arrayBufferView = new Uint8Array(imageAsArrayBuffer);

var blobImg = new Blob([ arrayBufferView ], { type: "image/" + imageFormat });

var formNode = put("form", {

  "method": "post",

  "enctype": "multipart/form-data"

});

var formData = new FormData(formNode);

formData.append("attachment", blobImg, imageName+"."+imageFormat));

esriRequest({

  url: "http://[server]/[instance]/rest/services/[folder]/[name]/FeatureServer/[layerid]/[oid]/addAttachment",

  form: formData,

  content: { f: "json" },

  handleAs: "json"

}).then(lang.hitch(this, function(response){

  alert("Attachment Success: " +response.addAttachmentResponse.success)

}), lang.hitch(this, function(error){

  console.warn(error);

}));

View solution in original post

IsaiahAguilera
Occasional Contributor II

John,

Thank you a ton for your response this is starting to get me to think this might work!  I had to ditch the base64 because of performance issues and went with a direct reference to the file. So I had to convert the FILE URI returned from the device Camera into a file object and from there was able to use a FileReader to convert the object to an arraybuffer to use with your provided sample.

          var reader = new FileReader();

          var arrayBuffer;

            window.resolveLocalFileSystemURI(fileURI, function (entry) {

                entry.file(function (s) {

                    arrayBuffer = reader.readAsArrayBuffer(s);

                }, function (e) {

                    console.log('ee');

                });

            });

                     

            var imageName = "someImageFilename";

            var imageFormat = "jpeg";

            var arrayBufferView = new Uint8Array(arrayBuffer);

            var blobImg = new Blob([arrayBufferView], {

                type: "image/" + imageFormat

            });

This worked great. I am however having issues with creating a form node. Your sample uses var formNode = put(... but I am unsure of where the "put" comes from.  Is this a dojo method?  I might just be tired and missing this but any clarification would  be great.  Thanks!

0 Kudos
JohnGrayson
Esri Regular Contributor

Load the "put-selector/put" module. You can also use dom-construct or any other way of creating a dom node.

John

IsaiahAguilera
Occasional Contributor II

John,

Your help was invaluable in getting this done! It is now working beautifully and I am very grateful!  The hardest part was getting the actual file converted into a blob but I was able to do so with the below code I am posting to help anyone else with this issue.

function onSuccess(fileURI) {

                window.resolveLocalFileSystemURL(fileURI, function (entry) {

                    var reader = new FileReader();

                    reader.onloadend = function (evt) {

                        var imageName = "someImageFilename";

                        var imageFormat = "jpg";

                        var arrayBufferView = new Uint8Array(evt.target.result);

                        var blobImg = new Blob([arrayBufferView], {

                            type: "image/jpeg"

                        });

                        var formNode = put("form", {

                            "method": "post",

                            "enctype": "multipart/form-data"

                        });

                        var formData = new FormData(formNode);

                        formData.append("attachment", blobImg, imageName + "." + imageFormat);

                        console.log("worked");

                        esriRequest({

                            url: "http://[server]/[instance]/rest/services/[folder]/[name]/FeatureServer/[layerid]/[oid]/addAttachment...,

                            form: formData,

                            content: {

                                f: "json"

                            },

                            handleAs: "json"

                        }).then(lang.hitch(this, function (response) {

                            console.log("Attachment Success: " );

                        }), lang.hitch(this, function (error) {

                            console.warn(error);

                        }));

                    };

                    entry.file(function (s) {

                        reader.readAsArrayBuffer(s);

                    }, function (e) {

                        console.log('Error');

                    });

                });

Once other thing that is not a huge issue but the

response.addAttachmentResponse.success

function you had in the success call for addAttachment was coming back undefined.  This didn't effect the actual addAttachment function though so I just removed it.  Not sure if there was a typo or something.  Anyways thank you for your help!

DougCarroll
Esri Contributor

John passing on my thanks as well.  I was not aware of these two JavaScript classes, nor would of seen the context on how they are helpful for uploading files.  This was a good post. 

Blob - Web API Interfaces | MDN

Uint8Array Object

-Doug

0 Kudos
MichaelKefahuchi
New Contributor

I just wish to express my thanx as well, this discussion helped me incredibly.

0 Kudos