Handling a data context loss
Glossary Item Box
Introduction
The mechanism that tracks data context loss on a record edit page enables you to detect changes (for example, when you go from a page to another section) automatically. If any changes were made on the page, the user will be notified about the unsaved changes and will be able to return to editing or leave the page without saving (Fig. 1).
Fig. 1. Potential changes loss warning
The structure of the context data loss tracking mechanism on a page
The structure of the context data loss tracking mechanism on a page includes:
- New methods and events of the Terrasoft.Component base component
- The CheckModuleDestroyMixin mixin.
- New and modified methods of the BasePageV2 base editing page.
New methods and events of the Terrasoft.Component base component.
The “canExecute()” method
The canExecute() method calls the canExecute event, and adds the callback function to its parameters – a link to the onClick() method, in which the canExecute() method was called. The canExecute event connects to the view model and calls the canBeDestroyed() method of the CheckModuleDestroyMixin mixin. This method may return false if there are any unsaved changes on the editing page. If all changes are saved, the method always returns true, and the execution of onСlick() is not interrupted. The canExecute() method implementation:
// Generates the canExecute event. // Returns true, if the onClick() method execution can continue. canExecute: function(config) { var args = config.args; var event = args[args.length - 1]; // If the onClick() method was called from the CheckModuleDestroyMixin mixin as a callback function, // then the last parameter signaling the interruption is passed to the event. if (event && event.isComeBack) { return true; } // Adding the event of method interruption to the arguments. // Required for stopping the execution of the method when onClick is called from the callback function. Array.prototype.push.call(config.args, { isComeBack: true }); // Applying the current context. Ext.apply(config, { scope: this }); // Generating the canExecute event. var canExecute = this.fireEvent("canExecute", config); return canExecute; },
The process of calling the canExecute() method occurs in the onClick() method of certain control elements (or in all other elements, called in the onClick() method). These control elements include the Terrasoft.Button base button, the Terrasoft.Grid list, the Terrasoft.BaseMenuItem menu elements, etc. If necessary, the process of calling this method can be added to other components as well. An example of the canExecute() method calling process in the Terrasoft.Grid component:
// The method that indicates the active list record. setActiveRow: function(newId) { var oldId = this.activeRow; if (!oldId && !newId) { return; } if (newId !== oldId) { var canExecute = oldId && this.canExecute({ method: this.setActiveRow, args: arguments }); // If CheckModuleDestroyMixin returns false, the method execution is interrupted. if (canExecute === false) { return; } ... } },
The OnGridClick() method handler is called upon clicking the Terrasoft.Grid class instance. OnGridClick() calls the setActiveRow() method in its turn. If there’s an existing active string, the canExecute() method is called in the setActiveRow() method. The configuration object is passed to the canExecute() method as an argument. The link to the setActiveRow() method and the arguments of setActiveRow() (which were used to call the method) are added to the properties of the configuration object. If the called event canExecute returns false, the work of the setActiveRow() method will be interrupted. However, the calling process of the setActiveRow() method can be restored since it was passed as a callback function.
The “canExecute” event
The canExecute event is called in the Terrasoft.Component base component constructor, and its generation occurs in the canExecute() method.
// Class constructor. constructor: function(config) { this.addEvents( ... "canExecute" ); ... }
In order to control component behavior in the configuration schema, you must associate the view model with the canExecute event. To do this, in the diff modification array of the BaseSectionV2 base section schema, define the binding of the canExecute event to the canBeDestroyed method in the DataGrid element. The canBeDestroyed method is defined in the CheckModuleDestroyMixin mixin.
// Modifications array of the basic list schema. diff: [ // Adding a list element. { "operation": "insert", "name": "DataGrid", "parentName": "DataGridContainer", "propertyName": "items", "values": { ... "canExecute": {"bindTo": "canBeDestroyed"}, ... } }...
The “CheckModuleDestroyMixin” mixin
The CheckModuleDestroyMixin mixin provides message exchange with open edit pages (including those that are open in a chain). Additionally, it is used to interrupt the execution of the method that called canExecute() (for example, the onClick() button method). This mixin is "mixed" into the view model of the configuration schema.
The message exchange with short editing pages is established by the updateCanBeDestroyedConfig() method:
// Updates the information about the ability to delete editing page context. updateCanBeDestroyedConfig: function() { // Creating a key. var cacheKey = this.Ext.String.format("{0}-cache", this.sandbox.id); // Saving to client cache by object key, used by the cards. this.Terrasoft.ClientPageSessionCache.setItem(cacheKey, { canBeDestroyed: true }); // Publishing a system broadcast message. this.sandbox.publish("CanBeDestroyed", cacheKey); // Updating work results of message subscribers. this.canBeDestroyedConfig = this.Terrasoft.ClientPageSessionCache.getItem(cacheKey); }
The display of the edit page message dialog and the result processing of user selection are both implemented in the showCanBeDestroyed() method:
// Displays a message in a dialog. showCanBeDestroyed: function(resumeConfig) { // A message from the page, displayed in the confirmation dialog. var message = this.getDestroyedMessage(); // Display the confirmation dialog. this.Terrasoft.showConfirmation(message, function(returnCode) { // If the user selects "Yes", the callback function is called. // This will continue execution of the interrupted handler for the component click event. if (returnCode === this.Terrasoft.MessageBoxButtons.YES.returnCode) { this.Ext.callback(resumeConfig.method, resumeConfig.scope || this, resumeConfig.args); } }, ["yes", "no"], this); }
New and modified methods of the BasePageV2 base editing page
The subscription to the CanBeDestroyed message (sent out by the CheckModuleDestroyMixin mixin) is implemented in the subscribeSandboxEvents() method:
// Message subscription. subscribeSandboxEvents: function() { ... this.sandbox.subscribe("CanBeDestroyed", this.onCanBeDestroyed, this); ... }
The onCanBeDestroyed() and the setNotBeDestroyedConfig() methods check if unsaved data exists:
// Checking unsaved data. onCanBeDestroyed: function(cacheKey) { // Receiving and checking the cache object. var config = this.Terrasoft.ClientPageSessionCache.getItem(cacheKey); if (!this.Ext.isObject(config)) { return; } var isChanged = this.isChanged(); // If the edit page has unsaved data, a message is generated and the object is changed in the cache. if (isChanged) { this.setNotBeDestroyedConfig(config); } }, ... // Forms a configuration object for displaying the message to the user. setNotBeDestroyedConfig: function(config) { // Determining the message shown to the user. var message = this.get("Resources.Strings.PageContainsUnsavedChanges"); Ext.apply(config, { // Unsaved data attribute. canBeDestroyed: false, // The message shown to the user. errorInfo: { message: message } }); }