Input time - Timepicker like datepicker in embeddedforms

Hi,

I need an input field with a timepicker. I use the datepicker for dates:
grafik

which is documented here:

Is there a similar thing available for time?

Regards,
Nicole

Hi @NickiMueller,

Try using the Angular UI timepicker component as per the below docs

Hello @hassang,

I tried it but I am not familiar with angular and setting up angular projects. I always get the error:

I copied the code in my camunda form:

<!doctype html>
<html ng-app="ui.bootstrap.demo">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  </head>
<body>
<form name="generatedForm" role="form">

<div ng-controller="TimepickerDemoCtrl">
 <div uib-timepicker ng-model="mytime" ng-change="changed()" hour-step="hstep" minute-step="mstep" show-meridian="ismeridian"></div>

  <pre class="alert alert-info">Time is: {{mytime | date:'shortTime' }}</pre>
  <div class="row"> 
    <div class="col-xs-6">
        Hours step is:
      <select class="form-control" ng-model="hstep" ng-options="opt for opt in options.hstep"></select>
    </div>
    <div class="col-xs-6">
        Minutes step is:
      <select class="form-control" ng-model="mstep" ng-options="opt for opt in options.mstep"></select>
    </div>
  </div>
  <hr>
  <button type="button" class="btn btn-info" ng-click="toggleMode()">12H / 24H</button>
  <button type="button" class="btn btn-default" ng-click="update()">Set to 14:00</button>
  <button type="button" class="btn btn-danger" ng-click="clear()">Clear</button>
</div>
  </form>
</body>
</html>

and added the example.js in the same folder:

angular.module('ui.bootstrap.demo', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('TimepickerDemoCtrl', function ($scope, $log) {
  $scope.mytime = new Date();

  $scope.hstep = 1;
  $scope.mstep = 15;

  $scope.options = {
    hstep: [1, 2, 3],
    mstep: [1, 5, 10, 15, 25, 30]
  };

  $scope.ismeridian = true;
  $scope.toggleMode = function() {
    $scope.ismeridian = ! $scope.ismeridian;
  };

  $scope.update = function() {
    var d = new Date();
    d.setHours( 14 );
    d.setMinutes( 0 );
    $scope.mytime = d;
  };

  $scope.changed = function () {
    $log.log('Time changed to: ' + $scope.mytime);
  };

  $scope.clear = function() {
    $scope.mytime = null;
  };
});

Any ideas?
Thank you, Nicole

Hi @NickiMueller,

Kindly find attached a simple working example
The same HTML form is used as a start and task form.
Please deploy the process and form together as in the below snip

test-html-form-process.bpmn (3.0 KB)

I am attaching the content of test-form.html as uploading HTML files to the forum is not allowed

<script cam-script type="text/form-script">

inject([ '$rootScope', '$scope', '$log', function($rootScope, $scope, $log) {

    $scope.newTestForm = {};
	
    $scope.newTestForm.isPnFormHeader = true;
	$scope.newTestForm.isPnFormHeaderOpen = true;
	
	$scope.newTestForm.isPnAssigneeActionVisible = false;
	$scope.newTestForm.isPnAssigneeActionDisabled = true;
    $scope.newTestForm.isPnAssigneeActionOpen = false;
	       
	var variableManager = camForm.variableManager;
	var taskService = camForm.client.resource('task');
	  
	$scope.loggedInUser = $rootScope.authentication.name;
	
	$scope.changed = function () {
		$log.log('Time changed to: ' + $scope.testBusinessObject.timeValue);
	};
			
	camForm.on('form-loaded', function () {
	
		if (!camForm.taskId) {
			// start form
			
			
			$scope.testBusinessObject = {};
			// initial value for timeValue
			$scope.testBusinessObject.timeValue = new Date();
		
			camForm.variableManager.createVariable({
				name: 'testBusinessObject',
				type: 'json',
				value: $scope.testBusinessObject
			});
			
		} else {
			// task form
			
			// tell the form SDK to fetch the json variable name 'testBusinessObject'
			variableManager.fetchVariable('testBusinessObject');
		}
	});
	
	camForm.on('variables-fetched', function () {

		if (camForm.taskId) {
			// task form
	
			taskService.get(camForm.taskId, function (err, task) {
				// console.log(JSON.stringify(task));
				
				switch (task.taskDefinitionKey) {
					case "ut-task1":
						// only visible for ut-task1						
				        $scope.newTestForm.isPnAssigneeActionVisible = true;
						$scope.newTestForm.isPnAssigneeActionDisabled = false;
						$scope.newTestForm.isPnAssigneeActionOpen = true;
						
				        break;
				
					default:
						$scope.newTestForm.isPnAssigneeActionVisible = false;
						$scope.newTestForm.isPnAssigneeActionDisabled = true;
						$scope.newTestForm.isPnAssigneeActionOpen = false;
				}
			});
		}
	});
	
	camForm.on('variables-restored', function() {
		// work with the variable (bind it to the current angularJS $scope)
		$scope.testBusinessObject = variableManager.variable('testBusinessObject').value;
	});
	
}]);
</script>

<div class="panel-group">
    <div class="panel panel-default">
        <div class="panel-heading" ng-click='newTestForm.isPnFormHeaderOpen = !newTestForm.isPnFormHeaderOpen'>
            <h5 class="panel-title">
				<span class="pull-right" ng-class="{'glyphicon glyphicon-menu-up':newTestForm.isPnFormHeaderOpen, 'glyphicon glyphicon-menu-down':!newTestForm.isPnFormHeaderOpen}" aria-hidden="true"></span>
				Test Form
            </h5>
        </div>
        <div class='panel-collapse collapse' ng-class="{'in' : newTestForm.isPnFormHeaderOpen}">
            <div class="panel-body">
               <fieldset>
                    <div class="form-group">
                        <div class="col-sm-12">
                            <label for="ctrTimeValue" class="control-label">Time Value</label>
                            <div id="ctrTimeValue" uib-timepicker 
							   ng-model="testBusinessObject.timeValue" 
							   ng-change="changed()" />
                        </div>
					</div>
				</fieldset>
            </div>
        </div>
    </div>
	
	<div class="panel panel-default" ng-if="newTestForm.isPnAssigneeActionVisible">
        <div class="panel-heading">
            <h4 class="panel-title">
				<span class="pull-right" ng-class="{'glyphicon glyphicon-menu-up':newTestForm.isPnAssigneeActionOpen, 'glyphicon glyphicon-menu-down':!newTestForm.isPnAssigneeActionOpen}" aria-hidden="true"></span>
                Assignee Action
            </h4>
        </div>
        <div class='panel-collapse collapse' ng-class="{'in' : newTestForm.isPnAssigneeActionOpen}">
            <div class="panel-body">
                Assignee Action Details
            </div>
        </div>
    </div>
	
</div>
1 Like

Hi @hassang,

thank you. I will test it with my application. That is what I looked for.
Thank you,
regards, Nicole

1 Like

Hi @hassang,
I now have the problem that I do not know how to bind the variable ‘timevalue’ to am cam-variable respectively delegateExecution object. I tried several possibilities but nothing worked.

In my EJB I want to read out the time variable with:

	public void saveTime(DelegateExecution delegateExecution) {
		Map<String, Object> variables = delegateExecution.getVariables();    
		Date thesisColloquiumTime = (Date) variables.get("timeValue");
	}

So I tried the following in my form:

  <div id="ctrTimeValue" uib-timepicker 
	   ng-model="testBusinessObject.timeValue" 
	  ng-change="changed()" cam-variable-name="timeValue" cam-variable-type="Date" />

That does not work, so I tried it with a separate input field:

<div class="col-sm-12">
     <label for="ctrTimeValue" class="control-label">Time Value</label>
               <div id="ctrTimeValue" uib-timepicker ng-model="testBusinessObject.timeValue" ng-change="changed()" />	
			<input cam-variable-name="timeValue" cam-variable-type="Date" ng-model="testBusinessObject.timeValue" />
 </div>

The third variant was to put the input field after the Time value div:

grafik

In this variant I can see the Input Field with the value but when I complete the task I get an error.
grafik

Error:
grafik

Any ideas would be great.
Thank you.
Nicole

Hi @NickiMueller,

In the example provided, JSON object is used to store the form’s data “testBusinessObject” so you can access the time value as below

JsonValue testBusinessObject = execution.getVariableTyped("testBusinessObject");
SpinJsonNode jsonNode = testBusinessObject.getValue();

jsonNode.prop("timeValue").value();

https://javadoc.io/doc/org.camunda.spin/camunda-spin-core/latest/org/camunda/spin/json/SpinJsonNode.html

If the requirement is to have time value stored in a separate process variable then below HTML content can be used.

Notice: the value of Date typed variable should be updated on form submission.

<script cam-script type="text/form-script">

inject([ '$rootScope', '$scope', '$log', function($rootScope, $scope, $log) {

    $scope.newTestForm = {};
	
    $scope.newTestForm.isPnFormHeader = true;
	$scope.newTestForm.isPnFormHeaderOpen = true;
	
	$scope.newTestForm.isPnAssigneeActionVisible = false;
	$scope.newTestForm.isPnAssigneeActionDisabled = true;
    $scope.newTestForm.isPnAssigneeActionOpen = false;
	       
	var variableManager = camForm.variableManager;
	var taskService = camForm.client.resource('task');
	  
	$scope.loggedInUser = $rootScope.authentication.name;
	
	$scope.changed = function () {
		$log.log('Time changed to: ' + $scope.testBusinessObject.timeValue);
	};
			
	camForm.on('form-loaded', function () {
	
		if (!camForm.taskId) {
			// start form
			
			
			$scope.testBusinessObject = {};
			// initial value for timeValue
			$scope.testBusinessObject.timeValue = new Date();
		
			camForm.variableManager.createVariable({
				name: 'testBusinessObject',
				type: 'json',
				value: $scope.testBusinessObject
			});
			
			camForm.variableManager.createVariable({
				name: 'timeValue',
				type: 'Date',
				value: $scope.testBusinessObject.timeValue
			});
			
		} else {
			// task form
			
			// tell the form SDK to fetch the variables
			variableManager.fetchVariable('testBusinessObject');
			variableManager.fetchVariable('timeValue');
		}
	});
	
	camForm.on('variables-fetched', function () {

		if (camForm.taskId) {
			// task form
	
			taskService.get(camForm.taskId, function (err, task) {
				// console.log(JSON.stringify(task));
				
				switch (task.taskDefinitionKey) {
					case "ut-task1":
						// only visible for ut-task1						
				        $scope.newTestForm.isPnAssigneeActionVisible = true;
						$scope.newTestForm.isPnAssigneeActionDisabled = false;
						$scope.newTestForm.isPnAssigneeActionOpen = true;
						
				        break;
				
					default:
						$scope.newTestForm.isPnAssigneeActionVisible = false;
						$scope.newTestForm.isPnAssigneeActionDisabled = true;
						$scope.newTestForm.isPnAssigneeActionOpen = false;
				}
			});
		}
	});
	
	camForm.on('variables-restored', function() {
		// work with the variable (bind it to the current angularJS $scope)
		$scope.testBusinessObject = variableManager.variable('testBusinessObject').value;
	});
	
	camForm.on('submit', function() {
		
		variableManager.variable('timeValue').value = $scope.testBusinessObject.timeValue;
	});
	
}]);
</script>

<div class="panel-group">
    <div class="panel panel-default">
        <div class="panel-heading" ng-click='newTestForm.isPnFormHeaderOpen = !newTestForm.isPnFormHeaderOpen'>
            <h5 class="panel-title">
				<span class="pull-right" ng-class="{'glyphicon glyphicon-menu-up':newTestForm.isPnFormHeaderOpen, 'glyphicon glyphicon-menu-down':!newTestForm.isPnFormHeaderOpen}" aria-hidden="true"></span>
				Test Form
            </h5>
        </div>
        <div class='panel-collapse collapse' ng-class="{'in' : newTestForm.isPnFormHeaderOpen}">
            <div class="panel-body">
               <fieldset>
                    <div class="form-group">
                        <div class="col-sm-12">
                            <label for="ctrTimeValue" class="control-label">Time Value</label>
                            <div id="ctrTimeValue" uib-timepicker 
							   ng-model="testBusinessObject.timeValue" 
							   ng-change="changed()" />
                        </div>
					</div>
				</fieldset>
            </div>
        </div>
    </div>
	
	<div class="panel panel-default" ng-if="newTestForm.isPnAssigneeActionVisible">
        <div class="panel-heading">
            <h4 class="panel-title">
				<span class="pull-right" ng-class="{'glyphicon glyphicon-menu-up':newTestForm.isPnAssigneeActionOpen, 'glyphicon glyphicon-menu-down':!newTestForm.isPnAssigneeActionOpen}" aria-hidden="true"></span>
                Assignee Action
            </h4>
        </div>
        <div class='panel-collapse collapse' ng-class="{'in' : newTestForm.isPnAssigneeActionOpen}">
            <div class="panel-body">
                Assignee Action Details
            </div>
        </div>
    </div>
	
</div>

Hi @hassang,
unfortunately the testBusinessObject is null

I used the html-form from the working example.
Any more ideas? :see_no_evil:
Thank you so much,
Nicole

Did you check the existence of the variable after form’s submission (from the cockpit app)?

May I know when you are trying to access the variable? Is it after form’s submission? or before?

Hi @NickiMueller,

Kindly find attached a working example with a task listener configured to be invoked on the complete event.


test-html-form-process.bpmn (3.4 KB)

Attached is the HTML form (Notice: remove the .form extension)
test-form.html.form (4.1 KB)

1 Like

I checked it, it is not visible in cockpit.

After submission

@hassang, I will check this later, thank you!

Hi @hassang ,
all your examples work, if I execute them standalone. But if I try to embedd them in my application there is always something that goes wrong. The last example throws an exception like this:
Caused by: org.graalvm.polyglot.PolyglotException: TypeError: Cannot read property 'getValue' of null

I think about reading in the time with normal input fields with type String and then convert it into type Date/Time… :see_no_evil: dirty but I think I can not spend more time in the other way.

Thank you anyway for your input and help.
Have a good day,
Nicole