ArcGIS JavaScript API V4 & Uploading a File to a Geoprocessing Service

4358
3
10-21-2019 09:58 PM
mdonnelly
Esri Contributor
5 3 4,358

Hello,

Recently I needed to upload a file to a geoprocessing service using the ArcGIS JavaScript API V4 but had trouble finding a concise road map on how to achieve this. After knocking my knees on the undergrowth I am writing this blog post so you can travel the road in comfort.

I note that others have provided information for this using v3 of the API but there are some differences that this post explores relating to v4.

The Problem:

  • Need to upload a file to a geoprocessing service
  • Using the ArcGIS JavaScript API v4 on the client

The Solution Overview:

  • Create a geoprocessing tool that takes a file as a parameter
  • Publish the tool as a geoprocessing service with the option to Upload enabled
  • In the JS code have a way of prompting the user to upload a file using a document form
  • Create a request to the Upload endpoint of the geoprocessing service, whose body is the contents of the form
  • An item ID will be returned from the request. This ID is then passed as the file parameter to the geoprocessing service job
  • The geoprocessing service reads the ID from the file parameter and automatically translates that to the path to the uploaded file location

Solution Details

Python:

There isn't anything special from the Python side of things. Simply grab the file parameter as text:

file_path = arcpy.GetParameterAsText(0)

 

The parameter will be a string that represents the path to the file. Once you have the path to the file you can manipulate the file as required for your purposes.

Geoprocessing Tool:

Create a geoprocessing tool in ArcMap or ArcPro with a parameter for a file with a data type of 'File'.

Matching the order of the parameter in the tool with the parameter index in the Python script is essential. If the file parameter is first in the toolbox list then this parameter has an index of zero in the Python parameter list.

tool parameters

This translates to the following in Python:

arcpy.GetParameterAsText(0)

Geoprocessing Service:

Run the tool in ArcMap or ArcPro so that it completes successfully.

In ArcMap, go to Geoprocessing Results, right click on the successful job and select Share As > Geoprocessing Service

In ArcPro, go to History, right click on the successful job and select Share As > Web Tool

To enable Upload capability:

  • ArcMap: In the service editor, under the Parameters section, tick the Upload box
  • ArcPro: In the share as web tool dialog, in the Configuration tab, tick the Upload box

Check the tool parameters are correct and add descriptions. Publish the tool, which now has the ability to upload files.

JavaScript & HTML

1. Use a document form to allow the user to nominate a file for upload:

<form enctype="multipart/form-data" method="post" id="uploadForm">
   <div class="field">
      <label class="file-upload">
         <span><strong>Add File</strong></span>
         <input type="file" name="file" id="inFile" />
      </label>
   </div>
</form>

2. Create a request to the geoprocessing service upload endpoint, that uses the form as the body:

document
 .getElementById("uploadForm")
 .addEventListener("change", function(event) {
   var fileName = event.target.value.toLowerCase();
   if (fileName.indexOf(".zip") !== -1) {
      //is file a zip - if not notify user
      uploadFile(fileName);
   } 
 }
 });

function uploadFile(fileName) {
    var name = fileName.split(".");
    // Chrome and IE add c:\fakepath to the value - we need to remove it
    // see this link for more info: http://davidwalsh.name/fakepath
    name = name[0].replace("c:\\fakepath\\", "");
    var upload = esriRequest(
       fileUploadUrl,
       {
          body: document.getElementById("uploadForm"),
          method: "post",
          responseType: "text" //Ideally would return as json but that doesn't seem to work for me
       }      
    ).then(uploadSucceeded, errBack);
 }
  

3. Handle the response of the request and extract the item ID, passing it as a parameter to the geoprocessing service:

function uploadSucceeded(result) {
 
 //Ideally the result would come back as json but as it is coming back as html it will need to be parsed for the itemid
 var element = document.createElement('html');
 var itemID = "";
 var itemURL = "";
 element.innerHTML = result.data;
 var tdElements = element.getElementsByTagName('td');

 for (let tdElement of tdElements){
    if (tdElement.innerHTML == "Item ID:"){
       itemID = tdElement.nextElementSibling.firstChild.innerHTML;
    }
 }

 if (itemID == ""){
    console.log("Could not get file item id");
    return
 }
 
 console.log("itemID: " + itemID)
 var params = {
    FileName: "{'itemID':'" + itemID + "'}" //Replaces the need for the DataFile object
 };

 gp.submitJob(params).then(handleResult, errBack, progTest);
}


Note that the JS API documentation recommends that you create a DataFile object, which you then pass as the parameter value. I could not get that to work and so constructed the object from JSON myself based on what I could see the geoprocessing service required. I determined the format of the JSON object by executing the geoprocessing service from the REST endpoint.

I have attached my full sample JS code for reference. This code not only uploads a file but also gets a response in the form of an object id of the uploaded feature. The feature is zoomed to and then a FeatureForm for that feature is opened for editing.  One caveat is that at the time of writing I could not get the update button to work on the FeatureForm, probably due to an unresolved asych issue.

3 Comments
About the Author
Specialising in ArcGIS Enterprise deployments