Multiple file uploads in the embedded form

Hello,

I ran into a small problem while doing the following:

  • I want to give the user of the task list the option to upload at least one file. There are 5 upload fields in total. Minimum one file upload is required and the rest 4 are optional.

  • When the user selects one file to upload but leaves the rest 4 empty I get a NullPointerException:

    java.lang.NullPointerException
    at org.camunda.bpm.engine.variable.impl.type.FileValueTypeImpl.createValue(FileValueTypeImpl.java:44)
    at org.camunda.bpm.engine.rest.dto.VariableValueDto.toTypedValue(VariableValueDto.java:118)
    at org.camunda.bpm.engine.rest.dto.VariableValueDto.toMap(VariableValueDto.java:147)
    at org.camunda.bpm.engine.rest.sub.repository.impl.ProcessDefinitionResourceImpl.submitForm(ProcessDefinitionResourceImpl.java:161)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

Is there any way I can make camunda ignore the file upload fields if they are empty? There is no “required” directive for it inside your camscript engine?

Thanks in advance for your help.

Kind regards,
Deniss

Hi Deniss,

This appears to be the problem discussed here: https://groups.google.com/forum/#!topic/camunda-bpm-users/llYPOUryqdI You could try the workarounds proposed there.

Cheers,
Thorben

Thanks Thorben,

I will give those options a try and report back.

Kind regards,
Deniss

Hello,

Unfortunately I have troubles with this type of solution:

camForm.on('submit', function() {
  camForm.variableManager.destroyVariable('requestDocument2');
});

I get this error during form submission:
The process could not be started. : Cannot read property 'type' of undefined

The input itself is like this:
<input cam-variable-name="requestDocument2" cam-variable-type="File" cam-max-filesize="10000000" type="file" id="requestDocument2" class="form-control" />

Any help would be appreciated. Thanks in advance.

Kind regards,
Deniss

Hello!

I have managed to complete my task and solve some obstacles while using multiple file upload forms (empty or not) throughout my process.

My process is quite simple:

  1. start form -> ability to attach 1 - 5 files;

  2. approve form -> ability to download / attach 1 - 5 files -> After submiting the form the process goes back to approve form step until all camunda user groups approve it. Users need a possibility to add/remove attachments during this approve form cycle;

  3. If somebody from any group rejects the form during approve form stage we have a next step -> review form - same as with approve form -> download / attach 1 - 5 files -> review details / change something / add or remove files -> submit form and go back to approve form.

Start Form

  1. Code to check and do necessary actions if the values for cam-variable-type=“file” are empty or not:

    camForm.on(‘submit’, function(evt) {
    var indexOfUploadFileField = 0;
    for (var i = 0; i < camForm.fields.length; i++) {

     			if (camForm.fields[i].variableName == 'requestDocument2') {
    
     				if (camForm.fields[i].element.context.value == '') {
     					indexOfUploadFileField = i;
     					camForm.fields.splice(indexOfUploadFileField, 1);
     					camForm.variableManager.destroyVariable('requestDocument2');
     				}
     			}
    
     			if (camForm.fields[i].variableName == 'requestDocument3') {
    
     				if (camForm.fields[i].element.context.value == '') {
     					indexOfUploadFileField = i;
     					camForm.fields.splice(indexOfUploadFileField, 1);
     					camForm.variableManager.destroyVariable('requestDocument3');
     				}
     			}
    
     			if (camForm.fields[i].variableName == 'requestDocument4') {
    
     				if (camForm.fields[i].element.context.value == '') {
     					indexOfUploadFileField = i;
     					camForm.fields.splice(indexOfUploadFileField, 1);
     					camForm.variableManager.destroyVariable('requestDocument4');
     				}
     			}
    
     			if (camForm.fields[i].variableName == 'requestDocument5') {
    
     				if (camForm.fields[i].element.context.value == '') {
     					indexOfUploadFileField = i;
     					camForm.fields.splice(indexOfUploadFileField, 1);
     					camForm.variableManager.destroyVariable('requestDocument5');
     				}
     			}
     		}
     	});
    
  2. Simple upload fields:

<input cam-variable-name="requestDocument2" cam-variable-type="File" cam-max-filesize="10000000" type="file" class="form-control" style="height: auto" />

Approve Form

  1. We must fetch the variables by REST:

camForm.on('variables-fetched', function() {

$scope.variablesResponseData = null;

inject(['$scope', '$http', 'Uri', function($scope, $http, Uri) {

			$scope.getUploadFileVariables = function() {

				$http({method: 'GET', url: Uri.appUri('engine://engine/:engine/task/' + camForm.taskId + '/variables/')}).
						then(function(response) {
							$scope.variablesResponseData = response;

							if ($scope.variablesResponseData.data.requestDocument2 !== undefined) {
								$scope.requestDocument2 = $scope.variablesResponseData.data.requestDocument2;
							} else {
								$scope.requestDocument2 = null;
							}

							if ($scope.variablesResponseData.data.requestDocument3 !== undefined) {
								$scope.requestDocument3 = $scope.variablesResponseData.data.requestDocument3;
							} else {
								$scope.requestDocument3 = null;
							}

							if ($scope.variablesResponseData.data.requestDocument4 !== undefined) {
								$scope.requestDocument4 = $scope.variablesResponseData.data.requestDocument4;
							} else {
								$scope.requestDocument4 = null;
							}

							if ($scope.variablesResponseData.data.requestDocument5 !== undefined) {
								$scope.requestDocument5 = $scope.variablesResponseData.data.requestDocument5;
							} else {
								$scope.requestDocument5 = null;
							}

						}, function(response) {

							$scope.data = response.data || "Request failed";
						});
				}

			$scope.getUploadFileVariables();

			$scope.uploadFile = function(fileName) {

				var formData = new FormData();
				formData.append('data', document.getElementById(fileName).files[0]);
				formData.append('valueType', 'File');
				$http.post(Uri.appUri('engine://engine/:engine/task/' + camForm.taskId + '/variables/'+ fileName +'/data'), formData, {

					transformRequest: angular.identity,
					headers: {'Content-Type': undefined}
				}).success(function() {
					$scope.getUploadFileVariables();
				});
			};

			$scope.deleteFile = function(fileName) {

				$http.delete(Uri.appUri('engine://engine/:engine/task/' + camForm.taskId + '/variables/'+ fileName), {
					headers: {
						'Content-Type': "application/json;charset=utf-8"
					}
				}).success(function() {
					$scope.getUploadFileVariables();
				})
			}
		}])
	});
  1. Then by using angular you can use the objects created above from rest and define the properties needed to run those functions above in order to upload / view / delete files.

Hope this helps out somebody in the future :slight_smile:
Kind regards,
Deniss

Hello! I’m new here, so first many thanks for this page, where I’ve learned a lot.
I would like to share my solution to upload 0…8 files (in the example I’ll provide 2 files).
1. Define the two input fields

    <div class="form-group" id="fileMaterialParts" ng-show="proc_chipbonding || proc_wirebonding || proc_pcb_assembly">
         <label for="fileMaterialParts" >Material parts <span style="color:red;">(required)</span></label>
         <input type="file" name="fileMaterialParts" 
             cam-variable-name="fileMaterialParts" cam-variable-type="File" ng-model="fileMaterialParts" />   
      </div>
      <div class="form-group" id="fileBondplan" ng-show="proc_chipbonding || proc_
         <label for="fileBondplan">Wirebond scheme <span style="color:red;">(required)</span></label>
         <input type="file" name="fileBondplan" id="fileBondplan" 
             cam-variable-name="fileBondplan" cam-variable-type="File" ng-model="fileBondplan" />
      </div>

2. Remove the unused cam-variables using JavaScript (taken from the post of Deniss_Makarenkov)

<script cam-script="cam-script" type="text/form-script">
  camForm.on('submit', function() {
    for (var i = camForm.fields.length -1; i>=0; i--) {
      if (camForm.fields[i].variableName == 'fileBondplan') {
                if (camForm.fields[i].element.context.value == '') {
                    camForm.fields.splice(indexOfUploadFileField, 1);
                    camForm.variableManager.destroyVariable('fileBondplan');
                }
            } else if (camForm.fields[i].variableName == 'fileMaterialParts') {
                if (camForm.fields[i].element.context.value == '') {
                    camForm.fields.splice(indexOfUploadFileField, 1);
                    camForm.variableManager.destroyVariable('fileMaterialParts');
                }
            }
    } // close for loop
 }); // close camForm.on
</script>

3. Show the file names with links for download on another HTML-form using AngularJS
Don’t forget to include camunda-bpm-sdk-angular.js and the angular.min.js !

<fieldset id="fieldsetFiles">
     <legend>File Upload</legend>
        <!-- the hidden input fields are needed to get the cam-variables -->
         <input type="hidden" cam-variable-name="fileMaterialParts" cam-variable-type="String" />
         <input type="hidden" cam-variable-name="fileBondplan" cam-variable-type="String" />
        <!-- the table shows only the available files -->
        <table  class="table">
            <tr><th>Purpose</th><th>File name</th></tr>
             <tr ng-repeat="var in camForm.variableManager.variables" ng-show="var.valueInfo.filename">
                <td>{{var.name}}</td>
        <td><a ng-href="http:/my-servers-address:8080/camunda/api/engine/engine/default/task/{{camForm.taskId + '/variables/' + var.name + '/data'}}">{{var.valueInfo.filename}}</a></td>
             </tr>
        </table>
    </fieldset>

4. Delete unused cam-file-variables
In this HTML-form the unused cam-file-variables must be deleted, like above in point no. 2!

5. Resume
This solution doesn’t need the injection to REST-API.
The exchange of a file (delete old filename and upload a new file) needs some more code.
But you can upload a new file to the same cam-file-variable, using the HTML-form-code of point no. 1.
A simple delete can be done by JavaScript or Angular.

3 Likes