How can I fetch json values from all the completed instances in a parallel Multi-Instance User Task Form?

Hi to all.

My issue is that when I complete a multi-instance user task form (“Select items”), I can’t get (see) all the values of my created json variable (“selectedItem”) in the next task form (“Gather total needs”) of my process. I can see only the last value.

Does anyone know how can I fetch all the values of a created json variable in case of a multi-instance task?

A screenshot of my process diagram:

My code snippet:

<form role="form" name="gatherNeeds">
	<script cam-script type="text/form-script">
		camForm.on('form-loaded', function() {													// The variable 'selectedItem' has not been loaded ("fetched") from the server yet.
			camForm.variableManager.fetchVariable('selectedItem');								// We tell the "Form SDK" to "fetch" the 'json' variable named 'selectedItem'.
		});
		camForm.on('variables-fetched', function() {											// The variable 'selectedItem' has been loaded ("fetched") from the server
			$scope.selectedItem = camForm.variableManager.variableValue('selectedItem');		// and is bound to the current AngularJS $scope of the form.
		});
	</script>
	<h2>Total List</h2>
	<div>
		<table style="width:100%;">
			<thead>
				<tr>
					<th style="width:140px;">Category</th>
					<th style="width:305px;">Brief Description</th>
					<th style="width:250px;">Detailed Description</th>
					<th style="width:75px;" >Price</th>
					<th style="width:50px;" >Quantity</th>
					<th style="width:100px;">Subtotal</th>
				</tr>
			</thead>
			<tbody>
				<tr ng-repeat="x in selectedItem track by $index">
					<td><input style="width:140px;" type="text" value="{{x.Category}}" readonly /></td>
					<td><input style="width:305px;" type="text" value="{{x.BriefDescription}}" readonly /></td>
					<td><input style="width:250px;" type="text" value="{{x.DetailedDescription}}" readonly /></td>
					<td><input style="width:75px;"  type="number" value="{{x.Price}}" readonly /></td>
					<td><input style="width:50px;"  type="number" value="{{x.Quantity}}" readonly /></td>
					<td><input style="width:100px;" type="number" value="{{x.Price * x.Quantity | currency}}" readonly /></td>
				</tr>
				<tr>
					<td><b>Total</b></td>
					<td></td>
					<td></td>
					<td></td>
					<td></td>
					<td><b>{{total | currency}}</b></td>
				</tr>
			</tbody>
		</table>
	</div>
</form>

Thank you,
Steve

@steftriant can you confirm that all of your values are in the JSON array?

Consider that everything you set in parallel executions is local, so the json variable may be always of one element, because is defined every time as new.

I never had the need to do this, but you could try use an external existing json map and add values to this one from inside the parallel execution and see what happens.

See Pattern Review: DMN Looping for Array Input for a example of merging your Json from a multi instance

Hi @Mizar01.

First of all thank you very much for your feedback. :slightly_smiling_face:

Yes, I 've realized that in case of a parallel multi-instance task, the engine doesn’t understand that this task is submitted from a number of different users and so, this is why after the completion of each instance, the values of created json variable are substituted by the new ones. So, I must find a way to keep and transfer the values from all the completed instances and not only from the last completed one. :face_with_raised_eyebrow:

Could you explain please how can I create an external existing json map?

Cheers,
Steve

Hi @StephenOTT.

Thank you for your feedback. :slightly_smiling_face:

Yes, I posted the piece of code from my parallel Multi-Instance User Task Form (“Select items”) where I add all the values of my previous JSON Array (“item”) into the new created one (“selectedItem”).

camForm.on('submit', function(evt) {																			// Before the "submit" request is sent to the server,
			var selectedItem = [];																						// We create a new Array as a variable named "selectedItem".
			angular.forEach($scope.item, function(x) {																	// For each item of the "item" Array 
				if (x.Quantity) {																						// if item's "quantity" input field has a value (so, item's "checkbox" is checked),
					selectedItem.push(x);																				// we add the selected item to the "selectedItem" Array	
				}
			})
			if (selectedItem.length<1) {																				// If no "item" has been selected from the table,
				evt.submitPrevented = true;																				// an event handler prevents the form from being submitted by setting the property "submitPrevented" to 'true'.
			} else {																									// If at least one "item" has been selected from the table, 
				camForm.variableManager.createVariable ({																// We "create" (declare) a new process variable
					name: 'selectedItem',																				// named 'selectedItem' and
					type: 'json',																						// provide as type information 'json' used for serialization.
					value: selectedItem																					 
				});	
			}
		});

But, as I also answered to @Mizar01, it seems that the engine keeps and transfers the submitted values from the last completed instance only and not also from the others. By some way, json values are substituted by the new submitted ones after the completion of each instance. So, I must find a way to keep and transfer to the next task form of my process the values from all the completed instances and not only from the last completed one. :face_with_raised_eyebrow:

I’m going to see your other post here :slightly_smiling_face:

Cheers,
Steve

Hi again @StephenOTT.

I 've read thoroughly your link post forum here (Pattern Review: DMN Looping for Array Input) but my process scenario differs a bit from your example in the fact that I don’t have to match multiple things to multiple users (Systems to users) as yours.
In my process scenario, I 've generated an array of users (“administrators”) in the Script task with javascript and I 've also created a JSON Array (“item”) in my 1st task form (“Configure specifications & items”) with camForm function. By this way, only 1 instance of the task (“Select items”) can be automatically assigned to each user (which is the desired in my case) but my problem starts after the completion of the Multi-Instance Task because I can’t keep and transfer the json values from all the completed instances but only from the last completed one.
Process engine substitutes each time the json values on the completion of each instance of the task. :confused:

Has anyone got any idea on this please?

A screenshot of my process:

Thank you,
Steve

@steftriant (assuming i understand your explanation): look in the DMN pattern for how I am updating the Json variable after each cycle of the DMN.

TLDR: You have your data from each task as part of the Multi-instance group of tasks. So on the Task listener for the end event, on each completion of the task, you add your output from the single task into the JSON array which is in the Process Instance scope (rather than in the Task scope). So after each completed Task, the Process Instance scoped json variable is updated. After all tasks are completed, you can see the outcome by getting the JSON Array.

Remember when you are updating the JSON Array it is not a simple overwrite. You are using the SPIN library’s append function to add new entries to the array

Hi @steftriant

I didn’t have time lately to see this forum and to give an example, but, as @StephenOTT said in other words, you have to create an external Json Map, and by external I mean it has to be created outside the subprocess.
If you create a var called ‘globalJson’ just before the sub process or multi instance starts, this variable will have a process instance scope. So if you add content to this variable, it will be added and not replaced.

Beware of the not so clear behavior of the variables created on the fly by camSDK inside the multi instance task or process. In the sub process you must take into account two things:

  • if you define the variables only in the camSdk, they are automatically created as they were global scoped, so, even you define a variable called singleJson, from this moment the variable will be shared among instances, and repeatedly overwritten. This isn’t what you want.
  • If you define the variable in the sub process (with setVariableLocal) and before calling a camSDK form, those variables will remain local.

I think you should define every single json submitted as local (so you have to declare it at the start of the multi instance, with an execution start listener for example). At the end of each instance you can use a complete task listener or an end execution listener to add the single json to the globalJson. You decide how to append the content.

In the end the globalJson variable will have every content submitted by all users.

Hi @StephenOTT and @Mizar01.

Thank you for your answers. I 'm going to take into account anything you told me here as soon as possible because I think that I need plenty of time and clear mind to understand those things and manage to apply them to my process scenario. To be honest, I’m not so experienced in many relative issues yet, so I must take my time.

I will let you know of course in any case for any possible outcome. :slightly_smiling_face:

Best regards,
Steve

Hi @steftriant.

I managed to upload a standalone example. You can start it from the tasklist.
It should open two parallel tasks and join the results.
All the process is logged on the server (catalina.out).

It’s not managing json, but it shows how to do it.

test_multi_instance.bpmn (4.6 KB)