- Developing Applications with Oracle JET
- Using the Common Model and Collection API
- Creating a CRUD Application Using Oracle JET
Creating a CRUD Application Using Oracle JET
Use Knockout and the Oracle JET Common Model API to create applications that perform CRUD (Create, Read, Update, Delete) operations on data returned from a REST Service API.
Topics:
Note:
The application shown in this section also includes code for defining and displaying header and footer detail. You can download the complete sample application here: OracleJET-CommonModel-CRUD.zip.
Defining the ViewModel
Identify the data source for your application and create the ViewModel.
- Identify your data source and examine the data. For data originating from a REST service, identify the service URL and navigate to it in a browser.
The following example shows a portion of the output of a REST service that returns department data for a fictitious organization from a REST server named
MockRESTServer.{ "Departments" : [ { "DepartmentId" : 10, "DepartmentName" : "Administration", "ManagerId" : null, "LocationId" : null, "version" : "ACED00057...contents truncated", "links" : { "self" : { "rel" : "self", "href" : "http://mockrest/stable/rest/Departments/10" }, "canonical" : { "rel" : "canonical", "href" : "http://mockrest/stable/rest/Departments/10" }, "Employees" : { "rel" : "child", "href" : "http://mockrest/stable/rest/Departments/10/Employees" } } }, { "DepartmentId" : 20, "DepartmentName" : "Retail Marketing", "ManagerId" : null, "LocationId" : null, "version" : "ACED00057...contents truncated", "links" : { "self" : { "rel" : "self", "href" : "http://mockrest/stable/rest/Departments/20" }, "canonical" : { "rel" : "canonical", "href" : "http://mockrest/stable/rest/Departments/20" }, "Employees" : { "rel" : "child", "href" : "http://mockrest/stable/rest/Departments/20/Employees" } } }, { ... contents omitted } ], "links" : { "self" : { "rel" : "self", "href" : "http://mockrest/stable/rest/Departments" } }, "_contextInfo" : { "limit" : 25, "offset" : 0 } }In this example, each department is identified by its
DepartmentIdand contains information about its name (DepartmentName), manager (ManagerId), and location (LocationId). Each department also contains employees (Employees) which are children of each department.Tip:
The Oracle JET Common Model CRUD sample application uses JSON data returned from a mock rest service. You can find the mock rest service scripts in thepublic_html/js/restfolder. You can find the sample JSON data in thedepartments.jsonfile located in thepublic_html/jsfolder. - Determine the data you will need for your collection.
For example, the following figure shows a simple Oracle JET table that uses the
DepartmentId,DepartmentName,LocationId, andManagerIdreturned from the REST service identified in the previous step to display a table of department IDs, names, location IDs, and manager IDs. The table element is defined as anoj-tableelement, which is included in the Oracle JET UI component library. - Add a JavaScript function to your application that will contain your ViewModel.
The following code shows a skeleton function that defines the ViewModel in the Oracle JET Common Model CRUD application. In this example, the function is stored in a file named
app.js. The code to complete the ViewModel will be defined in upcoming steps.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko) { function viewModel() { // To be defined }; return {'deptVM': viewModel}; } )Note:
This example uses RequireJS for modular development. The RequireJS bootstrap file will be shown in a later step. For additional information about using RequireJS, see Using RequireJS for Modular Development.
- Add a JavaScript function to the function you defined in the previous step that defines the data model using
oj.Model.extend().The highlighted code in the example below defines the data model for the application shown in the preceding figure. The
Departmentvariable represents a single record in the database and is displayed as a row in the table.Departmentis declared using theoj.Model.extendfunction call and instantiated in the declaration formyDept. TheurlRootproperty defines the data source, which in this case is the REST service URL.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko) { function viewModel() {var self = this;self.serviceURL = 'http://mockrest/stable/rest/Departments';; function parseDept(response) { if (response['Departments']) { var innerResponse = response['Departments'][0]; if (innerResponse.links.Employees == undefined) { var empHref = ''; } else { empHref = innerResponse.links.Employees.href; } return {DepartmentId: innerResponse['DepartmentId'], DepartmentName: innerResponse['DepartmentName'], links: {Employees: {rel: 'child', href: empHref}}}; } return {DepartmentId: response['DepartmentId'], DepartmentName: response['DepartmentName'], LocationId:response['LocationId'], ManagerId:response['ManagerId'], links: {Employees: {rel: 'child', href: response['links']['Employees'].href}}}; }// Think of this as a single database record or a single table row.var Department = oj.Model.extend({urlRoot: self.serviceURL,parse: parseDept,idAttribute: 'DepartmentId'});var myDept = new Department();}; return {'deptVM': viewModel}; }; }The
parseproperty is an optional user callback function to allow parsing of JSON record objects as they are returned from the data service. In this example,parseDeptis the callback function and simply maps theDepartmentIdandDepartmentNamereturned from the REST service toDepartmentIdandDepartmentName.If theLocationIdorManagerIdrecords contain data,parseDeptmaps the attributes toLocationIdandManagerId.The parse callback can be useful for mapping database attribute names to names that may make more sense. For example, if your database uses
IdandNameas the attributes that represent the department ID and department name, you could replace the return call in theparseDeptfunction with:return {DepartmentId: response['Id'], DepartmentName: response['Name']};For a complete list of
oj.Modelproperties and functions, see the oj.Model API documentation. - Define the collection that will hold the data model object you defined in the previous step using
oj.Collection.extend().The highlighted code in the example below defines the collection object for the
Departmentmodel object. TheDeptCollectionvariable is declared in theviewModel()function using theoj.Collection.extendfunction and instantiated in the declaration forself.DeptCol. Theurlproperty defines the data source, which in this case is the REST service URL, and limits the collection to 50 records.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko){ function viewModel() { var self = this; self.serviceURL = 'http://mockrest/stable/rest/Departments';self.Departments = ko.observableArray([]);self.DeptCol = ko.observable();self.datasource = ko.observable();var parseDept = function(response) { ...contents omitted}; var Department = oj.Model.extend({ urlRoot: self.serviceURL, parse: parseDept, idAttribute: 'DepartmentId' }); var myDept = new Department(); // this defines our collection and what models it will holdvar DeptCollection = oj.Collection.extend({url: self.serviceURL + "?limit=50",model: myDept});self.DeptCol(new DeptCollection());self.datasource(new oj.CollectionTableDataSource(self.DeptCol()));} return {'deptVM': viewModel}; } );Both the
DeptColanddatasourceobjects are defined as Knockout observables so that changes to the data collection can be handled. Thedatasourceobject will contain the column data needed by theoj-tableelement and is passed theDeptColobservable as a parameter tooj.CollectionTableDataSource().The
Departmentsobject is defined as a Knockout observable array and will be populated in a later step.For a complete list of
oj.Collectionproperties and functions, see the oj.Collection API documentation. - Populate the collection with data by calling
oj.Collection.fetch()to read the data from the data service URL.The highlighted code in the code sample below calls
oj.collection.fetch()to add data to theDeptColdata collection and complete the ViewModel.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko){ function viewModel() { var self = this; self.serviceURL = 'http://mockrest/stable/rest/Departments'; self.Departments = ko.observableArray([]); self.DeptCol = ko.observable(); self.datasource = ko.observable();self.fetch = function(successCallBack) {// populate the collection by calling fetch()self.DeptCol().fetch({success: successCallBack,error: function(jqXHR, textStatus, errorThrown){console.log('Error in fetch: ' + textStatus);}});};var parseDept = function(response) { ...contents omitted}; var Department = oj.Model.extend({ urlRoot: self.serviceURL, parse: parseDept, idAttribute: 'DepartmentId' }); var myDept = new Department(); var DeptCollection = oj.Collection.extend({ url: self.serviceURL + "?limit=50", model: myDept }); self.DeptCol(new DeptCollection()); self.datasource(new oj.CollectionTableDataSource(self.DeptCol())); } return {'deptVM': viewModel}; } );The
fetch()function also defines an error callback that will log a message to the console if thefetch()call fails. - Add the ViewModel or the file containing the name of your ViewModel to your RequireJS bootstrap file, typically
main.js.If you created your Oracle JET application using an Oracle JET Starter template or modified your Oracle JET download as described in Use RequireJS to Manage Library, Link, and Script References, you should already have a
main.jsfile. Locate the line that defines the require modules and add your file to the list.For example, the code below lists the modules defined for the Common Model Sample. The application stores its ViewModel in the
app.jsfile. The reference to theapp.jsfile is highlighted in bold.require(['ojs/ojcore', 'knockout', 'jquery','app', 'footer', 'MockRESTServer' 'ojs/ojmodel', 'ojs/ojknockout', 'ojs/ojknockout-model', 'ojs/ojdialog', 'ojs/ojinputtext', 'ojs/ojinputnumber', 'ojs/ojbutton', 'ojs/ojtable', 'ojs/ojcollectiontabledatasource'],You must also add the app reference in the callback definition as shown in the following example.
// this callback gets executed when all required modules are loaded function(ko, $, oj, app, footer, MockRESTServer) { ... } - Update your RequireJS bootstrap file to instantiate the ViewModel, create the Knockout bindings, and display the content on the page.
The highlighted code in the code sample below creates a Knockout observable for each element in the
deptDatacollection and assigns the resulting array to theDepartmentsKnockout observable array you defined in a previous step.require(['ojs/ojcore', 'knockout', 'jquery', 'app', 'footer', 'MockRESTServer' 'ojs/ojmodel', 'ojs/ojknockout', 'ojs/ojknockout-model', 'ojs/ojdialog', 'ojs/ojinputtext', 'ojs/ojinputnumber', 'ojs/ojbutton', 'ojs/ojtable', 'ojs/ojcollectiontabledatasource'], function(ko, $, oj, app, footer, MockRESTServer) // this callback gets executed when all required modules are loaded { var fvm = new footer.footerVM();$(document).ready(function(){$.getJSON("js/departments.json", function (data) { new MockRESTServer(data, {id:"DepartmentId", url:/^http:\/\/mockrest\/stable\/rest\/Departments(\?limit=([\d]*))?$/i, idUrl:/^http:\/\/mockrest\/stable\/rest\/Departments\/([\d]+)$/i});var vm = new app.deptVM();ko.applyBindings(fvm, document.getElementById('footerContent'));vm.fetch(function(collection, response, options){var deptData = collection;// This will create a ko.observable() for each element // in the deptData response and assign the resulting array // to the Departments ko observeableArray.vm.Departments = oj.KnockoutUtils.map(deptData, null, true);//perform a Knockout applyBindings() call binding this // viewModel with the current DOMko.applyBindings(vm, document.getElementById('mainContent'));//Show the content div after the REST call is completed.$('#mainContent').show();});});});} );
Reading Records
To read the records, define the Oracle JET elements that will read the records in your main HTML5 page.
The following sample code shows a portion of the index.html file that displays a table of records using the ViewModel defined in the previous steps and the oj-table element. In this example, the mainContent div includes the table definition that creates Department Id, Department Name, Location Id, and Manager Id as the table header text and defines the content for each row.
<div id="mainContent" class="oj-md-12 oj-flex-item page-padding" style="display: none;">
<div class="page-padding">
<oj-table id="table" data="[[datasource]]"
columns='[{"headerText": "Department Id",
"field": "DepartmentId", "sortable": "enabled"},
{"headerText": "Department Name",
"field": "DepartmentName", "sortable": "enabled"},
{"headerText": "Location Id",
"field": "LocationId"},
{"headerText": "Manager Id",
"field": "ManagerId"}]'>
</oj-table>
</div>
</div>
The data attribute reads the variable datasource from the REST service and binds it to the oj-table element.
Creating Records
To add the ability to create new records, add elements to your HTML5 page that accept input from the user and create a function that sends the new record to the REST server.
The figure below shows the result of adding a form using oj-input-* elements to the Oracle JET Common Model sample application. The user can enter a new department number in the provided field or use the side arrows to increment or decrement the value. The user then enters the name and clicks Add.
To add the ability to create new records to the application's ViewModel and HTML5 page:
- Add elements to the application's main page that accept input from the user.
The highlighted code in the example below adds
oj-input-*elements to theindex.htmlpage shown in the previous task.<div id="mainContent" class="oj-md-12 oj-flex-item page-padding" style="display: none;"> <div class="page-padding"><div id="deptList" class="oj-md-9 oj-flex-item"><oj-table id="table" summary="Demo Table" ...contents omitted</oj-table><br/><div id="addDept" class="oj-flex-item oj-md-3 oj-sm-12 right"><div id="quickUpdate" class="frame"><div id="newDeptForm"><div class="oj-form oj-sm-odd-cols-12 oj-md-odd-cols-6 oj-md-labels-inline"><h3>New Department</h3><hr/><div class="oj-flex"><div class="oj-flex-item"><oj-label for="newDepartId">Department Id</oj-label></div><div class="oj-flex-item"><oj-input-number id="newDepartId" value= "555"></oj-input-number></div></div><div class="oj-flex"><div class="oj-flex-item"><oj-label for="newDepartName">Department Name</oj-label></div><div class="oj-flex-item"><oj-input-text id="newDepartName" maxlength='30' placeholder="enter new name"></oj-input-text><oj-button id="saveBtn" on-oj-action="[[addDepartment]]" label='Add Department'></oj-button></div></div></div></div></div></div></div></div> </div>The form is defined to contain two input fields: an
oj-input-numberfor the department ID, and anoj-input-textfor the department name. Theoj-buttoncomponent is used for the form's button.The
oj-button'son-oj-actionattribute is bound to theaddDepartmentfunction which is defined in the next step. - Add code to the ViewModel to add the user's input as a new record (model) in the data collection.
The highlighted code in the example below shows the
addDepartment()function that adds the new department number and department name to theDeptColdata collection. In this example, the function calls theoj.Collection.create()method which creates the new model instance, adds it to the data collection, and saves the newDepartmentIdandDepartmentNameto the data service.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel'], function(oj, ko) { function viewModel() { var self = this; self.serviceURL = 'http://RESTServerIP:Port/stable/rest/Departments'; self.Departments = ko.observableArray([]); self.DeptCol = ko.observable(); self.datasource = ko.observable(); self.fetch = function(successCallBack) { ...contents omitted}; function parseDept(response){ ...contents omitted}; var Department = oj.Model.extend({ urlRoot: self.serviceURL, parse: parseDept,parseSave:parseSaveDept,idAttribute: 'DepartmentId' }); var myDept = new Department(); var DeptCollection = oj.Collection.extend({ url: self.serviceURL + "?limit=50", model: myDeptcomparator: 'DepartmentId'}); self.DeptCol(new DeptCollection()); self.datasource(new oj.CollectionTableDataSource(self.DeptCol()));function parseSaveDept(response){return {DepartmentId: response['DepartmentId'],DepartmentName: response['DepartmentName'],LocationId: response['LocationId'],ManagerId: response['ManagerId'],links: {Employees: {rel: 'child', href: response['links']['Employees'].href}}};};self.addDepartment = function (formElement, event) {var id = $("#newDepartId").val();var recordAttrs = {DepartmentId: id,DepartmentName: $("#newDepartName").val(),ManagerId: "", LocationId: "",links: {Employees: {rel: 'child', href: self.serviceURL + '/' + id + '/Employees'}}};this.DeptCol().create(recordAttrs,{'contentType': 'application/vnd.oracle.adf.resource+json',success: function (response) {console.log('Success in Create');},error: function(jqXHR, textStatus, errorThrown){console.log('Error in Create: ' + textStatus);}});}} return {'deptVM': viewModel}; } );The
oj.Collection.create()function accepts options to control the record save. In this example, simple error checking is added. In addition, thecreate()function sends acontentTypeto the REST server. Depending upon the REST service you are using, this option may not be required or may need modification.
Updating Records
To add the ability to update records, add elements to your HTML5 page that accept input from the user and create a function that sends the updated record to the REST server.
The figure below shows the Oracle JET Common Model sample application configured to allow updates to the department name. When the user moves the focus over a department name, a tooltip appears that prompts the user to click to edit. department name, a tooltip prompts the user to click to edit. If the user clicks the department name, a dialog appears that enables the user to change the name. The user can type in a new department name and click Change to update the record or Cancel to keep the existing department name.
To add the ability to update records to the application's ViewModel and HTML5 page:
- Add elements to the application's main page that identifies updatable elements and enables the user to perform an action to update them.
The highlighted code in the example below adds the
oj-dialogelement to the page and provides the prompt to the user to click to edit the page.<div id="mainContent" class="oj-flex-item oj-sm-12 oj-md-12 demo-page-content-area page-padding" style="display: none;"> <div class="page-padding"> <div id="deptList" class="oj-flex-item oj-md-9 oj-sm-12"> <oj-table id="table" data="[[datasource]]" columns='[{"headerText": "Remove", "id": "column1", "sortable": "disabled"}, {"headerText": "Department Id", "field": "DepartmentId", "sortable": "enabled"}, {"headerText": "Department Name", "field": "DepartmentName", "sortable": "enabled"}, {"headerText": "Location Id", "field": "LocationId"}, {"headerText": "Manager Id", "field": "ManagerId"}]' selectionMode='{"row": "none", "column": "none"}'row-renderer='[[oj.KnockoutTemplateUtils.getRenderer("row_tmpl", true)]]'> </oj-table> </div><oj-dialog id="editDialog" style="display:none" title="Change Department Name" dragAffordance="title-bar" modality="modeless" resize-behavior="none"><div class="oj-form oj-sm-odd-cols-12"><!-- Example of custom dialog header. Setting the class "oj-dialog-header" will tell the dialog to use the contents of that <div> as the header content. Leaving this out will cause the default header to be used, which uses the title attribute as the header content value. --><div class="oj-dialog-header oj-helper-clearfix" aria-labelledby="dialog-title-id"><div><span id="infoIcon" class="oj-message-status-icon oj-message-info-icon" style="float:left; margin-right: 10px"></span><span id="dialog-title-id" class="oj-dialog-title">Change Department Name</span></div></div><div class="oj-dialog-body"><div class="oj-md-odd-cols-4"><oj-label class="oj-label oj-label-inline" for="newName">Department Name</oj-label><oj-input-text id="newName" value="{{currentDeptName}}"></oj-input-text></div></div><div class="oj-dialog-footer"><oj-button id="submitBtn" on-oj-action="[[updateDeptName]]" label="Change"></oj-button><oj-button id="resetBtn" on-oj-action="[[cancelDialog]]" label="Cancel"></oj-button></div></div></oj-dialog></div> </div> </div> </div><script type="text/html" id="row_tmpl"><tr><td><div id='deptId' data-bind="text: DepartmentId"></div></td><td><div id="deptName" data-bind="text: DepartmentName, click: function(data, event){$root.showChangeNameDialog(DepartmentId,data,event)}"></div></td><td><div id="locId" data-bind="text: LocationId"></div></td><td><div id="mgrId" data-bind="text: ManagerId"></div></td></tr></script>The
oj-dialogelement includes theoj-dialog-header,oj-dialog-body, andoj-dialog-footerformatting classes. Theoj-dialog-headerclass is optional and is used in this example to format theInfoicon and title.The
oj-dialog-bodyclass formats the dialog body which includes theoj-labelforDepartment Nameand anoj-input-textelement to capture the user's input. Theoj-dialog-footerdefines twooj-buttoncomponents which add theChangeandCancelbuttons to the dialog. When the user clicks Change, theupdateDepartmentName()function handles the updates to the record.The original table is also modified to define the
row-rendererattribute which specifies therow_tmpltemplate to use for the row display. The template script calls theshowChangeNameDialog()function to display the dialog.The
updateDepartmentName()andshowChangeNameDialog()functions are defined in the next step. For additional information about theoj-dialogcomponent, see the oj-dialog API documentation. - Add code to the ViewModel to update the record.
The highlighted code in the example below shows the
updateDepartment()andshowChangeNameDialog()functions.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko) { function viewModel() { var self = this; self.serviceURL = 'http://mockrest/stable/rest/Departments'; self.Departments = ko.observableArray([]);self.currentDeptName = ko.observable('default');self.workingId = ko.observable('');self.DeptCol = ko.observable(); self.datasource = ko.observable(); self.fetch = function(successCallBack) { ...contents omitted}; function parseDept(response){ ...contents omitted} function parseSaveDept(response){ ...contents omitted} var Department = oj.Model.extend({ urlRoot: self.serviceURL, parse: parseDept, parseSave:parseSaveDept, idAttribute: 'DepartmentId' }); var myDept = new Department(); var DeptCollection = oj.Collection.extend({ url: self.serviceURL + "?limit=50", model: myDept comparator: 'DepartmentId' }); self.DeptCol(new DeptCollection()); self.datasource(new oj.CollectionTableDataSource(self.DeptCol()));self.showChangeNameDialog = function(deptId, data, event) {var currName = data.DepartmentName;self.workingId(deptId);self.currentDeptName(currName);document.getElementById("editDialog").open();}self.updateDeptName = function(formData, event) {var currentId = self.workingId();var myCollection = self.DeptCol();var myModel = myCollection.get(currentId);var newName = self.currentDeptName();if (newName != myModel.get('DepartmentName') && newName != '') {myModel.save({'DepartmentName': newName}, {success: function(myModel, response, options) {document.getElementById("editDialog").close();},error: function(jqXHR, textStatus, errorThrown) {alert("Update failed with: " + textStatus);document.getElementById("editDialog").close();}});} else {alert('Department Name is not different or the new name is not valid');document.getElementById("editDialog").close();}};return {'deptVM': viewModel}; } );The
showChangeNameDialog()function stores the selected department detail and opens the dialog with the existing department name shown in theoj-input-textfield.The
updateDepartment()function calls theoj.Model.save()method to save the currentModelobject to the data source. The function also defines success and error callbacks to close the dialog upon success or issue an error message if the record was not updated.
Deleting Records
To add the ability to delete records, add elements to your HTML5 page that accept input from the user and create a function that sends the new record for deletion to the REST server.
The figure below shows the Oracle JET Common Model CRUD application configured to allow record deletion. The user can check one or more departments in the list and click Remove Department to delete the record or records.
To add the ability to delete records to the application's ViewModel and HTML5 page:
- Add elements to the application's main page that identifies records marked for deletion and enables the user to perform an action to delete them.
The highlighted code in the example below adds the
Removecolumn with a check box to the department list and adds theRemove Departmentbutton below the list.<div id="mainContent" class="oj-flex-item oj-sm-12 oj-md-12 demo-page-content-area page-padding" style="display: none;"> <div class="page-padding"> <div id="deptList" class="oj-flex-item oj-md-9 oj-sm-12"> <oj-table id="table" data="[[datasource]]" columns='[{"headerText": "Remove", "id": "column1", "sortable": "disabled"},{"headerText": "Department Id", "field": "DepartmentId", "sortable": "enabled"}, {"headerText": "Department Name", "field": "DepartmentName", "sortable": "enabled"}, {"headerText": "Location Id", "field": "LocationId"}, {"headerText": "Manager Id", "field": "ManagerId"}]' selectionMode='{"row": "none", "column": "none"}'row-renderer='[[oj.KnockoutTemplateUtils.getRenderer("row_tmpl", true)]]'></oj-table> <br/><button id="deleteDept_btn" data-bind="enable: somethingChecked, click: deleteDepartment">Remove Department</button></div> </div> </div><script type="text/html" id="row_tmpl"><tr><td><input type="checkbox" data-bind="attr: {id: DepartmentId}, click: $root.enableDelete"/></td><td><div id='deptId' data-bind="text: DepartmentId"></div></td> <td><div id="deptName" data-bind="text: DepartmentName, click: function(data, event){$root.showChangeNameDialog(DepartmentId,data,event)}"></div></td> <td><div id="locId" data-bind="text: LocationId"></div></td> <td><div id="mgrId" data-bind="text: ManagerId"></div></td></tr></script>The original table is modified to include the
Removecolumn. Therow-rendererattribute specifies therow_tmpltemplate to use for the row display. The template script adds thecheckboxinput element to the first column and the value ofDepartmentId,DepartmentName, andLocationIdto the remaining columns.The button's
clickaction is bound to thedeleteDepartmentfunction which is created in the next step. - Add code to the ViewModel to delete the record or records submitted by the user.
The highlighted code in the example below shows the
deleteDepartment()function. In this example, the function calls theoj.Collection.remove()method which removes the model or models from the data collection. To delete the record from the data source, the function calls theoj.Model.destroy()method.define(['ojs/ojcore', 'knockout', 'ojs/ojmodel', 'MockRESTServer'], function(oj, ko) { function viewModel() { var self = this; self.serviceURL = 'http://mockrest/stable/rest/Departments'; self.Departments = ko.observableArray([]); self.DeptCol = ko.observable(); self.datasource = ko.observable();self.somethingChecked = ko.observable(false);self.fetch = function(successCallBack) { ...contents omitted} var Department = oj.Model.extend({ urlRoot: self.serviceURL, idAttribute: 'DepartmentId' }); var myDept = new Department(); var DeptCollection = oj.Collection.extend({ url: self.serviceURL + "?limit=50", model: myDept comparator: 'DepartmentId' }); self.DeptCol(new DeptCollection()); self.datasource(new oj.CollectionTableDataSource(self.DeptCol()));self.enableDelete = function() {if (!$('input[type=checkbox]:checked').length) {self.somethingChecked(false);} else {self.somethingChecked(true);}return true;}self.deleteDepartment = function(data, event) {var deptIds = [];deptIds = self.findDeptIds();var collection = data.DeptCol();deptIds.forEach(function(value, index, arr) {var model = collection.get(parseInt(value));if (model) {collection.remove(model);model.destroy();}});self.enableDelete();$('#table').ojTable('refresh');}self.findDeptIds = function() {var selectedIdsArray = [];$("input:checkbox").each(function() {var cb = $(this);if (cb.is(":checked")) {selectedIdsArray.push(cb.attr("id"));}});return selectedIdsArray;}} return {'deptVM': viewModel}; } );The
deleteDepartment()function calls thefindDeptIds()function which returns the list of selected departments marked for deletion. TheenableDelete()function resets the check box after the department list is deleted.



