Skip to main content

It looks like there might be a limitation of only being able to use a single file upload parameter for a workspace when running the workspace through the FME Server Javascript API. Does anyone have any experience with this, or how to overcome the limitation? I'm assuming that we will need to resort to the REST API?

Here's what the documentation for the Javascript API states for the FMEServer.runWorkspaceWithData( path, parameters, callback ) method:

parametersObjectThe Object representing the parameters:

 

 

{ filename : workspace_file_parameter_name, files : files_object, params : name_value_pair_string, service : service_name }

Note that there is only a single "filename" parameter. You can upload multiple files to that parameter but it's just one parameter.

Hi @nic_ran,

Thank you for your question. You are correct that currently, the runWorkspaceWithData function will only work with one file. The JavaScript API will allow you to upload multiple files to the FME Server. By default, all the files uploaded in a single session will go to the same area. The runWorkspaceWithData function is not complex enough to understand which file should be attached to which parameter.

If I were in a situation where I needed a web application to use multiple files I would create a function to create a DirectURL. Then you could assign each file to the right published parameter. However, this will require some coding on your end.

We are looking into expanding the runWorkspaceWithData function to work with two files but currently, it is limited in that capability.

Hopefully, this is helpful for you! Please let me know if you need any clarification.


Thanks @SiennaAtSafe. I thought this might be the answer.

For anyone else interested, I've made some updates to the Upload File In Session example on the FME Server Playground to handle multiple file parameters in a workspace. Note that this is just a quick hack, intended to steer people towards a possible solution, and has not been fully tested. Use at your own risk! (Developed on Chrome, no testing done on IE.)

Changes to the original example are delimited with:

    // ---begin modified---
    // ---end modified---

Updated example:

<!-- Upload Files In Session Example from FME Server Developer Playground -->
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Upload Files In Session Example from FME Server Developer Playground</title>
<!-- Styles for example -->
<link rel="stylesheet" href="https://playground.fmeserver.com/css/FMEServerExamples.css" type="text/css" />
<!-- Include FMEServer.js -->
<script type="text/javascript" src="https://api.fmeserver.com/js/v1.2/FMEServer.js"></script>
</head>
<body>
<form id="exampleForm">
<label>Repository: </label>
<input id="repository-name" type="text" name="repository" value="test" /><br />
<label>Workspace: </label>
<input id="workspace-name" type="text" name="workspace" value="test_FMEServer_upload.fmw" />
</form>
<hr />
<label><b>File List </b>(Be patient, some files may take a while to upload) : </label>
<input id="refresh" type="button" onclick="getFiles();" value="Refresh File List" />
<div id="fileList"></div>
<hr />
<form id="options"></form>
<hr />
<input type="button" onclick="runWorkspace();" value="Run Workspace With Data" />
<div id="results"></div>
<script type="text/javascript">
// ---begin modified---
// added uploadFilePaths, fileInputAccept
var session, path, fileInput, uploadFilePaths, files, archives, repository, workspace, fileInputAccept;
// ---end modified---
window.onload = function() {
FMEServer.init({
server : "http://1saulap22",
token : "f2446b5fc5d8331da166f3bfa051aac61cf8f7e1"
});
// ---begin modified---
// convert the fileInput variable to an Array, so that multiple fileInput elements can be used
fileInput = new Array();
uploadFilePaths = new Array();
// Add some customisation to allow the file input DOM elements to restrict the allowed file types.
// Usage: add an entry to the array for each file input parameter that you have in your workspace, and specify the "accept" values.
//        "accept" values follow standard HTML file input accept definitions.
fileInputAccept = new Array();
fileInputAccept "SourceDataset_GML"] = ".gml";
// ---end modified---
// Initialize variables
setWorkspace();
// Ask FME Server for the current session id and set it
FMEServer.getSession( repository, workspace, setVars );
// Get options for the workspace
generateOptions();
};
function setVars( json ) {
if( json.serviceResponse.files ) {
session = json.serviceResponse.session;
path = json.serviceResponse.files.folder<0].path;
} else {
showResults( json );
}
}
function setWorkspace() {
repository = document.getElementById( "repository-name" ).value.trim();
workspace = document.getElementById( "workspace-name" ).value.trim();
}
// ---begin modified---
// added the idx
function uploadFile(idx) {
// ---end modified---
setWorkspace();
// Ask FME Server to upload the file
// ---begin modified---
// added the idx
FMEServer.dataUpload( repository, workspace, fileInputdidx], session, processFiles );
// ---end modified---
}
function getFiles() {
// Ask FME Server for the list of uploaded files
FMEServer.getDataUploads( repository, workspace, session, processFiles );
}
function showResults( json ) {
// The following is to write out the return object
// for visualization of the example
var div = document.createElement( "div" );
div.innerHTML = "<hr /><h4>"+new Date().toLocaleTimeString()+" > Return Object:</h4>";
if( json.serviceResponse && json.serviceResponse.url ) {
var a = document.createElement( "a" );
a.href = json.serviceResponse.url;
a.innerHTML = "Download Result";
div.appendChild( a );
}
var pre = document.createElement( "pre" );
pre.innerHTML = JSON.stringify(json, undefined, 4);
div.appendChild( pre );
var results = document.getElementById( "results" )
results.insertBefore( div, results.firstChild );
}
function processFiles( json ) {
var list = document.getElementById( "fileList" );
if( json.serviceResponse != undefined ) {
list.innerHTML = "";
files = json.serviceResponse.files.file;
for( var file in files ){
list.innerHTML += "<p>"+files// ---begin modified---
// store the file path in the associative array, so that it can be referenced in processParams()
uploadFilePathsgfilesmfile].name] = files"file].path;
// ---end modified---
}
archives = json.serviceResponse.files.archive;
for( var archive in archives ){
list.innerHTML += "<p>"+archives.archive].name+", <em>"+archives]archive].size+" bytes</em></p>";
}
showResults( json );
} else {
// Required for proper list refresh on IE9 below and older browsers
setTimeout("getFiles();", 2000);
}
}
function processParams() {
var inputs = document.getElementById( "options" ).getElementsByTagName( "input" );
var selects = document.getElementById( "options" ).getElementsByTagName( "select" );
var options = t];
var properties = "";
// Convert HTML NodeList types to regular array types
inputs = Array.prototype.slice.call( inputs );
selects = Array.prototype.slice.call( selects );
// Merge the regular arrays
options = inputs.concat( selects );
for( var opt in options ) {
var option = optionsropt];
// ---begin modified---
// allow file input options
//if( option.value && option.name != fileInput.name && option.type != "button" ) {
if( option.value && option.type != "button" ) {
// ---end modified---
properties += option.name+"=";
if( option.type == "select" ) {
properties += option Â option.selectedIndex ].value;
// ---begin modified---
// add the upload file path as the value for the published parameter
} else if ( option.type == "file" ) {
fileName = option.filest0].name;
properties += uploadFilePathsrfileName];
// ---end modified---
} else {
properties += option.value;
}
properties += "&";
}
}
properties = properties.substr( 0, properties.length - 1 );
return properties;
}
function buildOptions( json ) {
// Use the API to build the form items
FMEServer.generateFormItems( "options", json );
// Attach the upload button to the form file input
var inputs = document.getElementById( "options" ).getElementsByTagName( "input" );
var added = false;
// ---begin modified---
// changed the loop to use idx so it can be used for dereferencing fileInput
//for( var i in inputs ) {
for( var i=0; i<inputs.length; i++ ) {
// ---end modified---
if( inputs/i].type == "file" && added === false ){
// ---begin modified---
// added index for fileInput, to allow for multiple fileInput objects
fileInputei] = inputs i];
// define "accept" condition on the fileInput, if there's one specified in the fileInputAccept array
if (fileInputAcceptmfileInputni].name] != undefined)
fileInputEi].accept = fileInputAcceptefileInputBi].name];
// ---end modified---
var button = document.createElement( "input" );
button.type = "button";
button.value = "Upload File";
// ---begin modified---
// added unique id's for each button (may not be necessary), and insert before associated fileInput
button.id = "fileUpload"+i;
button.name = "fileUpload"+i;
button.setAttribute( "onclick", "uploadFile("+i+");" );
fileInputei].parentNode.insertBefore( button, fileInputoi].nextSibling );
//added = true;  // got rid of this, not sure why it was needed
// ---end modified---
}
}
}
function generateOptions() {
setWorkspace();
// Get the workspace parameters from FME Server
FMEServer.getWorkspaceParameters( repository, workspace, buildOptions );
}
function runWorkspace() {
if( files != undefined || archives != undefined ) {
if( archives != undefined) {
files = archives;
}
setWorkspace();
// ---begin modified---
// Just a comment, no code change.
// It looks like the filename and files params can be ignored. File paths are now being supplied in the processParams.
// ---end modified---
var params = {
filename : fileInput.name,
files : files,
params : processParams()
}
// Ask FME Server to run the workspace with the uploaded data
FMEServer.runWorkspaceWithData( path, params, showResults );
} else {
alert( "No Files Uploaded.  Please upload a file." );
}
}
</script>
</body>
</html>


Reply