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