Using JSDOs to create mobile and web clients : Accessing standard CRUD and Submit operations : Delete operation example : Client JavaScript code: Delete
  
Client JavaScript code: Delete
The following examples illustrate calling remove( ) on a table reference in the JSDO to delete a record in JSDO memory, then calling saveChanges( ) on the dsCustomer JSDO without Submit to delete the corresponding record in the server database (along with any other pending record-change operations), and using both an afterDelete 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('afterDelete', onAfterDelete);

/* some code that deletes a record and sends it to the server */
var jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
  return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.remove();}

/* 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 onAfterDelete (jsdo , record , success , request ) {
    /* check for errors on any Delete operation */
    if (success) {
        /* do the normal thing for a successful Delete operation.
           for example, log the deleted record to the console  */
           console.log("Deleted Customer record for: " + record.data.Name);
        }
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('afterDelete', onAfterDelete);

/* some code that deletes a record and sends it to the server */
var jsrecord = dsCustomer.ttCustomer.find(function(jsrecord) {
  return (jsrecord.data.Name === 'Lift Tours');
});
if (jsrecord) {jsrecord.remove();};

/* 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 onAfterDelete (jsdo , record , success , request ) {
    /* check for errors on any Delete operation */
    if (success) {
        /* do the normal thing for a successful Delete operation.
           for example, log the deleted record to the console  */
           console.log("Deleted Customer record for: " + record.data.Name);
        }
record.acceptRowChanges();
    }
    else {
        /* all error messages handled by the Promise.fail() callback */
record.rejectRowChanges();
}
};
This sample code:
*Subscribes a callback function, onAfterDelete, to the afterDelete event to enable error-checking and manipulation of the record after the Delete operation completes on the server, which includes the client logging the deleted record. 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 afterUpdate event callbacks for the app as required.)
*Finds a record in the ttCustomer table with the customer name, 'Lift Tours' and deletes the record from JSDO memory.
*Sets autoApplyChanges on the dsCustomer JSDO to false. Setting autoApplyChanges to false allows each Delete 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 removal 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 onAfterDelete) 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.