I'm trying to develop a widget to allow the upload of a DWG file, which will be the input of a Geoprocessing service. I have the Geoprocessing Service published with the 'upload' capability enabled and set to Asynchronous, and "Maximum Number of Records Returned by Server:" set to like 100,000
I am using Experience Builder developer edition 1.9, with ArcGIS Enterprise 10.9. I should also note it is written in Type Script.
Currently I am struggling to get the upload/upload portion of the Geoprocessing service to work. I've posted my code below. I am uing the jimu TextInput component, set to type="file", and I am trying to trigger the upload/upload function on the onChange trigger
I've tried using esriRequest as reading the following documentation, it seems to be what I need to upload a file. And I am passing the file object into the esriRequest as the "Body" which is what it states in the documentation.
https://developers.arcgis.com/javascript/latest/api-reference/esri-request.html
import React from "react";
import {Label,TextInput} from "jimu-ui";import { esriRequest } from "esri/request";const AddFileTab = () => {const onFileInputChangeHandler = async function execute(evt😞 Promise<void> {const file_input = evt.target.valueconst url = "XXXX/GPServer/uploads/upload"esriRequest(url, {body: file_input,method : "post",responseType : "json"}).then((response) => {console.log(response);})}const renderer = () => {return (<div className={""}><Label >Select file</Label><TextInputonAcceptValue={function noRefCheck(){}}type="file"onChange = {onFileInputChangeHandler}/></div>)}return renderer();}
However, I get the following error
widget.tsx?cacc:16 Uncaught (in promise) TypeError: (0 , esri_request__WEBPACK_IMPORTED_MODULE_2__.esriRequest) is not a function
at Object.eval (widget.tsx?cacc:16:1)
at Generator.next (<anonymous>)
at eval (widget.tsx:14:71)
at new Promise (<anonymous>)
at __awaiter (widget.tsx:10:12)
at Object.execute [as onChange] (widget.tsx?cacc:11:1)
at index.js:3033:364
at Generator.next (<anonymous>)
at index.js:3010:1749
at new Promise (<anonymous>)
Can any suggest any solutions? Or would anyone be willing to share if they've managed to solve this functionality before? I have scoured the web but I can't find any other solutions specifically in Experience Builder and using TypeScript.
Any help would be greatly appreciated!
Solved! Go to Solution.
Hi there,
The error suggests that its not importing esriRequest correctly. Looking at what you have in your import statement, you are trying to import a non-default export by using the {}, esriRequest, is the default export, can you try changing the import statement to
import esriRequest from 'esri/request'
instead of
import {esriRequest} from 'esri/request'
Below is a utils file we have that we use for the GP services that require upload functionality.
import { getAppStore } from "jimu-core";
import esriRequest from "esri/request";
import Geoprocessor from 'esri/tasks/Geoprocessor';
export default class GeoprocessingUtils {
uploadUrl: string;
token: string;
gp: Geoprocessor;
constructor(url: string, isUploadSupported: boolean = false) {
this.token = getAppStore().getState().token;
const serverUrl = getAppStore().getState().portalUrl.replace("portal", "server");
const gpUrl = serverUrl + url + "?token=" + this.token;
this.gp = new Geoprocessor({ url: gpUrl });
if (isUploadSupported) {
const urlArr = url.split("/GPServer/");
this.uploadUrl = (urlArr.length > 1) ? serverUrl + urlArr[0] + "/GPServer/uploads/upload" : "";
} else {
this.uploadUrl = "";
}
}
uploadFile = async (file: any): Promise<string> => {
let form = new FormData();
form.append('file', file);
form.append("f", "json");
form.append("title", file.name);
form.append("name", file.name);
form.append("type", file.type);
form.append("token", this.token);
form.append("filename", file.name);
let upload = await esriRequest(this.uploadUrl, {
method: "post", body: form
}).then(this.uploadSucceeded, this.uploadFailed)
.catch((error) => {
console.error('An error occured uploading the file: ' + error);
return null;
});
if (upload) {
return upload;
} else {
return null;
}
}
executeTaskAsyn = async (params: any): Promise<any> => {
let response = await this.gp.submitJob(params)
.then(async (jobInfo) => {
console.log(jobInfo);
var jobid = jobInfo.jobId;
var options = {
interval: 1500,
statusCallback: function (j) {
console.log("Job Status: ", j.jobStatus);
}
};
return this.gp.waitForJobCompletion(jobid, options).then(async () => {
return this.gp.getResultData(jobid, "result").then((result) => {
return result.value;
}).catch(error => {
console.error(error);
return { "error": "Failed to run geoprocessing task" };
});
});
})
.catch((error) => {
console.error(error)
let errorMessages = error.messages.filter(msg => msg.type === 'error');
//the first error is the error message from gp output parameter
if (errorMessages.length > 0) {
return { "error": errorMessages[0].description }
} else {
return { "error": "Failed to run geoprocessing task" };
}
});
if (response) {
return response;
}
}
uploadSucceeded = (response) => {
var itemID = response["data"]["item"].itemID;
console.log("File upload successful, item ID: ", itemID);
return itemID;
}
uploadFailed = (response) => {
console.log("Failed: ", response);
return null;
}
}
Hope that helps.
Hi there,
The error suggests that its not importing esriRequest correctly. Looking at what you have in your import statement, you are trying to import a non-default export by using the {}, esriRequest, is the default export, can you try changing the import statement to
import esriRequest from 'esri/request'
instead of
import {esriRequest} from 'esri/request'
Below is a utils file we have that we use for the GP services that require upload functionality.
import { getAppStore } from "jimu-core";
import esriRequest from "esri/request";
import Geoprocessor from 'esri/tasks/Geoprocessor';
export default class GeoprocessingUtils {
uploadUrl: string;
token: string;
gp: Geoprocessor;
constructor(url: string, isUploadSupported: boolean = false) {
this.token = getAppStore().getState().token;
const serverUrl = getAppStore().getState().portalUrl.replace("portal", "server");
const gpUrl = serverUrl + url + "?token=" + this.token;
this.gp = new Geoprocessor({ url: gpUrl });
if (isUploadSupported) {
const urlArr = url.split("/GPServer/");
this.uploadUrl = (urlArr.length > 1) ? serverUrl + urlArr[0] + "/GPServer/uploads/upload" : "";
} else {
this.uploadUrl = "";
}
}
uploadFile = async (file: any): Promise<string> => {
let form = new FormData();
form.append('file', file);
form.append("f", "json");
form.append("title", file.name);
form.append("name", file.name);
form.append("type", file.type);
form.append("token", this.token);
form.append("filename", file.name);
let upload = await esriRequest(this.uploadUrl, {
method: "post", body: form
}).then(this.uploadSucceeded, this.uploadFailed)
.catch((error) => {
console.error('An error occured uploading the file: ' + error);
return null;
});
if (upload) {
return upload;
} else {
return null;
}
}
executeTaskAsyn = async (params: any): Promise<any> => {
let response = await this.gp.submitJob(params)
.then(async (jobInfo) => {
console.log(jobInfo);
var jobid = jobInfo.jobId;
var options = {
interval: 1500,
statusCallback: function (j) {
console.log("Job Status: ", j.jobStatus);
}
};
return this.gp.waitForJobCompletion(jobid, options).then(async () => {
return this.gp.getResultData(jobid, "result").then((result) => {
return result.value;
}).catch(error => {
console.error(error);
return { "error": "Failed to run geoprocessing task" };
});
});
})
.catch((error) => {
console.error(error)
let errorMessages = error.messages.filter(msg => msg.type === 'error');
//the first error is the error message from gp output parameter
if (errorMessages.length > 0) {
return { "error": errorMessages[0].description }
} else {
return { "error": "Failed to run geoprocessing task" };
}
});
if (response) {
return response;
}
}
uploadSucceeded = (response) => {
var itemID = response["data"]["item"].itemID;
console.log("File upload successful, item ID: ", itemID);
return itemID;
}
uploadFailed = (response) => {
console.log("Failed: ", response);
return null;
}
}
Hope that helps.
Excellent - thank you. Changing the " import esriRequest" worked. And the way you format the Params was what I need.
Thanks again
@Colome would you be willing to share your updated code to show how you got it working. I'm running into a similar issue and am struggling to get the upload to work.
@Grant-S-Carroll Can you please help me on how to create the custom widget for Experience Builder - Upload the CAD .dwg file