Using JSDOs to create mobile and web clients : Accessing standard CRUD and Submit operations : Update operation example : Client JavaScript code: Update
  
Client JavaScript code: Update
The following examples illustrate calling assign( ) on a table reference in the JSDO to update a record in JSDO memory, then calling saveChanges( ) on the dsCustomer JSDO without Submit to update the corresponding record in the server database (along with any other pending record-change operations), 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 updates a record and sends it to the server */
var jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.assign( {State: 'VT'} );}

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

dsCustomer.autoApplyChanges = false;
dsCustomer.saveChanges(false).done( /* Successful method execution */
function( jsdo, success, request ) {
/* all resource operations invoked by saveChanges() 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;

}).fail( /* Unsuccessful method execution */
    function( jsdo, success, request ) {
        /* one or more resource operations invoked by saveChanges() failed */
        var lenErrors,
errors,
errorType;

/* handle all operation errors */
errors = jsdo.ttCustomer.getErrors();
lenErrors = errors.length;
for (var idxError=0; idxError < lenErrors; idxError++) { /* Each error */
console.log(JSON.stringify(errors[idxError]));
}
});

function onAfterUpdate (jsdo , record , success , request ) {
/* check for errors on any Update operation */
if (success) {
/* do the normal thing for a successful Update operation.
for example, process updated record according to its Balance value */
if (record.data.Balance > $100000.00) {
/* process a high balance condition . . . */
}
record.acceptRowChanges();
}
else {
        /* all error messages handled by the Promise.fail() callback */
record.rejectRowChanges();
}
};
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 updates a record and sends it to the server */
var jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.assign( {State: 'VT'} );};

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

dsCustomer.autoApplyChanges = false;
dsCustomer.saveChanges(false).done( /* Successful method execution */
function( jsdo, success, request ) {
/* all resource operations invoked by saveChanges() 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;

}).fail( /* Unsuccessful method execution */
    function( jsdo, success, request ) {
        /* one or more resource operations invoked by saveChanges() failed */
        var lenErrors,
errors,
errorType;

/* handle all operation errors */
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) { /* log all error text
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);
}
}
});

function onAfterUpdate (jsdo , record , success , request ) {
/* check for errors on any Update operation */
if (success) {
/* do the normal thing for a successful Update operation.
for example, process updated record according to its Balance value */
if (record.data.Balance > $100000.00) {
/* process a high balance condition . . . */
}
record.acceptRowChanges();
}
else {
        /* all error messages handled by the Promise.fail() callback */
record.rejectRowChanges();
}
};
This sample code:
*Subscribes a callback function, onAfterUpdate, to the afterUpdate event to enable error-checking and manipulation of the updated record after the Update operation completes on the server, which includes client processing of the record based on a high balance condition. This callback accepts or rejects changes to each record based on the success of the corresponding operation. Otherwise, it ignores and defers all error message handling to the fail() callback registered on the Promise returned by saveChanges( ). (Typically, you code similar afterCreate and afterDelete event callbacks for the app as required.)
*Finds a record in the ttCustomer table with the customer name, 'Lift Tours', which has an initial State field value of 'MA', and changes its state to 'VT'. (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 operation event callback accepts or rejects the changes for each record, based on the operation success.
*Calls saveChanges(false) (without Submit) to invoke all pending Data Object operations one record at a time on the server, including update of the existing record with the customer name, 'Lift Tours'. It thereby synchronizes the content of JSDO memory with the server database for one record-change operation at a time across the network. A returned Promise object handles the overall success or failure of saveChanges( ) after all pending Create, Update, and Delete (CUD) operations complete.
For a successful saveChanges( ) invocation without Submit, the done() callback averages the balances of all client records for selected State field values. For an unsuccessful saveChanges( ) invocation, the fail() callback handles all error messages returned in response to invoking each CUD operation across the network.
Note: For unsuccessful operation results in this example, record changes are rejected before any associated error information is processed. However, the error messages for all operations remain available to the getErrors( ) method until the next call to fill( ) or saveChanges( ).
Note: Any event handler callback functions (such as onAfterUpdate) always execute before any registered Promise callback methods (such as done()). For an invocation of saveChanges( ) without Submit, the event callbacks execute after each CUD operation completes and returns its results from the server, and the appropriate registered Promise callbacks execute only after all results from these CUD operations have been returned from the server. This allows the results of all CUD operations 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 operation event callbacks.