Saving and restoring custom data and widgets

The Capture OnTheGo (COTG) app stores the values of the input fields to the local repository of the app upon closing the Form. On reopening the Form the original input fields and their values are restored. However, dynamically added widgets (see Dynamically adding COTG widgets) don't get restored. This needs to be handled in code. This topic explains how to do that.

Adding event listeners

In the process of closing and opening a Form two important events are triggered by the COTG library:

  • olcotgsavestate. This event is meant for custom scripts to save information when the user closes or submits the Form. It occurs after the state of all static input fields has been saved.
  • olcotgrestorestate​. This event allows custom scripts to do something when the Form is reopened. It occurs after all static inputs have been restored.

To latch on to these events, you have to register a olcotgsavestate​ listener and a olcotgrestorestate listener, respectively, on the ​​window object. The ​​window object represents a window containing a DOM (document object model), in this case the COTG Form.
The function callback on its addEventListener method allows you to implement custom code as part of the save and restore processes.
(For more information about the addEventListener method see the documentation: Mozilla and w3schools.)

The following code registers the olcotgsavestate ​listener on the ​​window object.

window.addEventListener('olcotgsavesta​​te', function(event) {
/* code to save custom data */
}); ​

The following snippet does the same for the restore process.

window.addEventListener('olcotgrestoresta​​te', function(event) {
/* code to retrieve custom data and restore custom widgets */
});

The following code combines the previously saved string with the restored URL of a (static) COTG Camera element:

window.addEventListener("olcotgrestorestate", function(event) {
	var value = event.detail.state["myString"];
	value = value + $("#camera1 img").attr("src");
	$("form p").html(value);
};
You should not register for these events after the document has loaded (e.g. on the $(document).ready() event), because these events might get triggered before the document is ready.

Place your code in a separate JavaScript file and make sure to include that file in the Web context or in the Web section that contains the COTG Form (see Including a JavaScript file in a Web context). For this file, the order in which JavaScript files are included in the template doesn't matter.

Handling the save and restore events

The code inside the function callback of the added event listeners should respond to the event, by saving or retrieving custom information, respectively.
When the COTG app saves the Form, you can store extra information in the event.detail.state object as follows:
event.detail.state["key"] = value;
The key can be any string, as long as that string isn't the same as the ID of one of the widgets on the Form.
In the code that handles the olcotgrestorestate event, use the same key to retrieve the stored information.

The following sample saves the value "test" using "myString" as the key, when the Form is saved:

window.addEventListener("olcotgsavestate", function(event) {
        event.detail.state["myString"] = "test";
});

The following code retrieves the value that was stored with the myString key and displays it in a paragraph (a <p> element) at the top of the form.

window.addEventListener("olcotgrestorestate", function(event) {
        var value = event.detail.state["myString"];
        $("form p").html(value);
};
When you've used jQuery to register for the events - $(window).on() - you must use event.originalEvent in the event handler functions, for example:
$(window).on("olcotgsavestate", function(event) {
        event.originalEvent.detail.state["mywidget"] = "test";
});

Restoring widgets

When a COTG Form is reopened, the app restores all input fields and widgets that were already present in the original Form (i.e. the Form deployed via Workflow or ​​sent as test using the Designer). Dynamically added widgets don't get restored. To restore dynamically added widgets, you have to:

  • Save information that reveals which widgets were added dynamically, and save the values of their input fields.
    This code should go in the event handler for the olcotgsavestate event.
  • Add and initialize the widgets again after the Form is reopened. Make sure to put any saved values back in the HTML.
    This code should go in the event handler for the olcotgrestorestate event.
  • Trigger the restore-state.cotg event on the newly added widget, to make sure that it is displayed correctly. For example:
    $('#myCamera").trigger('restore-state.cotg', event.detail.state);
    Put this code in the event handler for the olcotgrestorestate. event.
    Note that the widget must have the same ID as before in order to be able to retrieve its state.

For a detailed example, see: Saving and restoring Camera widgets.

Example

Saving and restoring Camera widgets

This example demonstrates a way to save and restore dynamically added Camera widgets. How to add Camera widgets is explained in another topic: Dynamically adding COTG widgets.

When a user takes or selects a picture with a Camera widget, the COTG app stores the path to the image that was taken or selected in a hidden input. This is the path to the image on the device that runs the COTG app. On submitting the Form the COTG app replaces this value - the path - with the actual image data.
In this example the hidden fields of dynamically added Camera elements have got the .camera-dyn class. In the event handler for the olcotgsavestate event, the jQuery each() method is used to iterate over all inputs that have this class, storing their name and value in an object.
Next, this object is stored - in JSON format - in the event.detail.state data with the key my-camera-data​.

window.addEventListener('olcotgsavestate', function(event) {
var camObj = {};
$('input.camera-dyn').each(function(){
var camera = $(this).attr('name');
var val = $(this).val();
camObj[camera] = val;
});​
event.detail.state['my-camera-data'] = JSON.stringify(camObj);​​
});​

In the olcotgrestorestate event handler the previously stored JSON is read from the event.detail.state and parsed into a JavaScript object. A for ... in ​loop is then used to iterate over the keys (the camera names) in that object. Inside this loop the cameras are added by calling the addCamera() function with the ID and value (the path to the picture) of each Camera element. Subsequently the restore-state.cotg event of the new widget is called to make sure that the thumbnail of the picture is shown and the Clear button becomes visible.

window.addEventListener('olcotgrestorestate', function(event) {
var json = JSON.parse(event.detail.state['my-camera-data']);
for (var cameraID in json) {
var value = json[cameraID];
addCameraWidget(cameraID,value);
$('#' + cameraID).trigger('restore-state.cotg', event.detail.state);
}
});

function addCameraWidget(cameraID, value) {
if(typeof value == 'undefined') {
value = '';
}
var html = '<label>Camera' +
'<div id="' + cameraID + '" role="cotg.PhotoWidget">' +
'<div class="panel" role="control-wrapper" style="position:relative;">' +
'<img role="photo" src="">' +
'<input role="photo-data" class="camera-dyn" name="' + cameraID + '" type="hidden" value="' + value + '">' +
'</div>' +
'<button class="small" role="take-button" type="button">Take now</button>' +
'<button class="small" role="pick-button" type="button">Library</button>' +
'<button class="small" role="clear-button" type="button">Clear</button>' +
'</div></label>';
$('#cameras').append(html); // add the camera object to the DOM
$('#' + cameraID).cotgPhotoWidget(); // init COTG widget