Using JSDOs to create mobile and web clients : Accessing standard CRUD and Submit operations : Submit operation example : Client JavaScript code: Submit
  
Client JavaScript code: Submit
The following examples illustrate calling add( ), assign( ), and remove( ) on a table reference in the JSDO to create, update, and delete records in JSDO memory, then calling saveChanges(true) (with Submit) on a dsCustomer JSDO to apply all the corresponding record changes (along with any other pending record changes) to the server database in a single request, and using both an afterUpdate event handler and a returned Promise object to handle the results.
This example uses simple error handling to log the contents of each error object returned by the JSDO getErrors( ) method:
/* subscribe to event */
dsCustomer.ttCustomer.subscribe('afterUpdate', onAfterUpdate);

/* some code that adds a record to JSDO memory */
var jsrecord = dsCustomer.ttCustomer.add( {State : 'MA'} );

/* some code that updates a record in JSDO memory */
jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.assign( {State: 'VT'} );}

/* some code that deletes a record from JSDO memory */
jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Burrows Sport Shop');
});
if (jsrecord) {jsrecord.remove();}

/* some other JSDO memory record changes . . . */

dsCustomer.autoApplyChanges = false;
dsCustomer.saveChanges(true).done( /* Successful Submit operation */
function( jsdo, success, request ) {
/* all record changes processed by the Submit succeeded */
/* for example, track the average customer balance in certain states */
var avgBalance = { MA : 0.0, maCount : 0,
VT : 0.0, vtCount : 0 };
jsdo.ttCustomer.foreach( function(jsrecord) {
if (jsrecord.data.State === 'MA') {
/* sum balances for customers in MA . . . */
avgBalance.MA += jsrecord.data.Balance;
avgBalance.maCount += 1;
}
if (jsrecord.data.State === 'VT') {
/* sum balances for customers in VT . . . */
avgBalance.VT += jsrecord.data.Balance;
avgBalance.vtCount += 1;
}
});
/* compute averages and process further . . . */
avgBalances.MA = avgBalances.MA / avgBalances.maCount;
avgBalances.VT = avgBalances.VT / avgBalances.vtCount;
jsdo.acceptChanges(); /* Accept all record changes */
}).fail( /* Unsuccessful Submit operation */
function( jsdo, success, request ) {
/* one or more record changes processed by the Submit failed */
var lenErrors,
errors,
errorType;

/* handle Submit operation errors */
console.log("Operation: Submit");
errors = jsdo.ttCustomer.getErrors();
lenErrors = errors.length;
for (var idxError=0; idxError < lenErrors; idxError++) { /* Each error */
console.log(JSON.stringify(errors[idxError]));
}
jsdo.rejectChanges(); /* Reject all record changes */
/* NOTE: Where an error occurred on the Submit invocation, thus
preventing the back end from processing the changes, you might
want to retry the Submit after the error conditions have been
cleared.
});

function onAfterUpdate (jsdo , record , success , request ) {
/* check for errors on any record update in the Submit operation */
if (success) {
/* do the normal thing for a successful record update.
for example, process updated record according to its Balance value */
if (record.data.Balance > $100000.00) {
/* process a high balance condition . . . */
}
}
else {
/* all error messages handled by the Promise.fail() callback */
}
};
This example is identical to the previous one but with more complex error handling to log the contents of each error object using more readable output:
/* subscribe to event */
dsCustomer.ttCustomer.subscribe('afterUpdate', onAfterUpdate);

/* some code that adds a record to JSDO memory */
var jsrecord = dsCustomer.ttCustomer.add( {State : 'MA'} );

/* some code that updates a record in JSDO memory */
jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.assign( {State: 'VT'} );};

/* some code that deletes a record from JSDO memory */
jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Burrows Sport Shop');
});
if (jsrecord) {jsrecord.remove();};

/* some other JSDO memory record changes . . . */

dsCustomer.autoApplyChanges = false;
dsCustomer.saveChanges(true).done( /* Successful Submit operation */
function( jsdo, success, request ) {
/* all record changes processed by the Submit succeeded */
/* for example, track the average customer balance in certain states */
var avgBalance = { MA : 0.0, maCount : 0,
VT : 0.0, vtCount : 0 };
jsdo.ttCustomer.foreach( function(jsrecord) {
if (jsrecord.data.State === 'MA') {
/* sum balances for customers in MA . . . */
avgBalance.MA += jsrecord.data.Balance;
avgBalance.maCount += 1;
}
if (jsrecord.data.State === 'VT') {
/* sum balances for customers in VT . . . */
avgBalance.VT += jsrecord.data.Balance;
avgBalance.vtCount += 1;
}
});
/* compute averages and process further . . . */
avgBalances.MA = avgBalances.MA / avgBalances.maCount;
avgBalances.VT = avgBalances.VT / avgBalances.vtCount;
jsdo.acceptChanges(); /* Accept all record changes */
}).fail( /* Unsuccessful Submit operation */
function( jsdo, success, request ) {
/* one or more record changes processed by the Submit failed */
var lenErrors,
errors,
errorType;

/* handle Submit operation errors */
console.log("Operation: Submit");
errors = jsdo.ttCustomer.getErrors();
lenErrors = errors.length;
for (var idxError=0; idxError < lenErrors; idxError++) { /* Each error */
switch(errors[idxError].type) {
case progress.data.JSDO.DATA_ERROR:
errorType = "Server Data Error: ";
break;
case progress.data.JSDO.RETVAL:
errorType = "Server App Return Value: ";
break;
case progress.data.JSDO.APP_ERROR:
errorType = "Server App Error #"
+ errors[idxError].errorNum + ": ";
break;
case progress.data.JSDO.ERROR:
errorType = "Server General Error: ";
break;
case default:
errorType = null; // Unexpected errorType value
break;
}
if (errorType) {
console.log("ERROR: " + errorType + errors[idxError].error);
if (errors[idxError].id) { /* error with record object */
console.log("RECORD ID: " + errors[idxError].id);
/* possibly log the data values for record with this ID */
}
if (errors[idxError].responseText) {
console.log("HTTP FULL TEXT: "
+ errors[idxError].responseText);
}
}
else { /* unexpected errorType */
console.log("UNEXPECTED ERROR TYPE: "
+ errors[idxError].type);
}
}
jsdo.rejectChanges(); /* Reject all record changes */
/* NOTE: Where an error occurred on the Submit invocation, thus
preventing the back end from processing the changes, you might
want to retry the Submit after the error conditions have been
cleared.
});

function onAfterUpdate (jsdo , record , success , request ) {
/* check for errors on any record update in the Submit operation */
if (success) {
/* do the normal thing for a successful record update.
for example, process updated record according to its Balance value */
if (record.data.Balance > $100000.00) {
/* process a high balance condition . . . */
}
}
else {
/* all error messages handled by the Promise.fail() callback */
}
};
This sample code:
*Subscribes a single callback function, onAfterUpdate, to the afterUpdate event to enable specific data manipulation for updates to an existing record that is returned from the server. The manipulation on a successful record update includes processing the record based on a high balance condition. This callback ignores and defers all error handling to the fail() callback registered on the Promise returned by saveChanges( ). (You might also code similar afterCreate and afterDelete event callbacks for the app as required.)
*Performs a variety of record changes in JSDO memory as part of the Submit operation (Note: The table reference can be omitted if ttCustomer is the only temp-table in the dsCustomer ProDataSet.)
*Sets autoApplyChanges on the dsCustomer JSDO to false. Setting autoApplyChanges to false allows each Update or other record-change operation attempted by saveChanges( ) to be identified and handled, either after each operation returns its response to the client using an event callback (as in the example) or after all operations have returned their responses using a Promise callback (also, as in the example). However, you must manually invoke the appropriate JSDO method to accept or reject the changes in JSDO memory, depending on the operation success and its requirements. In this example, the Promise callbacks accept or reject the changes for all records, based on the success of the overall Submit operation.
*Calls saveChanges(true) (with Submit) to send all pending record changes to the server in a single request, and thereby synchronizes the content of JSDO memory with the server database in a single Data Object operation across the network. A returned Promise object handles the overall success or failure of the Submit operation after all pending record changes complete.
For a successful Submit invocation, the done() callback averages the balances of all client records for selected State field values and accepts all record changes. For an unsuccessful Submit invocation, the fail() callback handles all types of errors returned for the Submit operation and rejects all record changes.
Note: Where a network or server error has prevented the Submit operation from executing on the server, you might want to retry the Submit after the associated network or server error has cleared.
Note: Any event handler callback functions (such as onAfterUpdate) always execute before any registered Promise callback methods (such as done()), and for a Submit operation, all such callbacks execute only after all results for the Submit have been returned from the server. This allows the results of all record changes to be processed together on the client. Although this example uses Promise callbacks in addition to operation event callbacks, all accepting and rejecting of JSDO memory changes is done in the Promise callbacks.