In this write-up, we review a JavaScript application we recently ported to Backendless. The application is an “editable invoice” which automatically saves its data including invoice line items, customer address, your own address, invoice number, etc. It is a good example demonstrating how to work with “related persistent data”, which means you can save a hierarchy or objects containing other objects (the “Invoice” object, contains a collection of “Line Items”). The application also demonstrates the functionality of user registration and login, although we stopped short of connecting the invoices with the user accounts (which would be fairly simple to add).
The Editable Invoice application is an effort by noBackend.org which helps to educate the developers about the advantages of BaaS. The vision is to provide a reference implementation with various backends.
The source code for the application has been pushed to our Github account.
Follow the steps below to setup and see the application in action:
Backendless.initApp("PUT-YOUR-APP-ID-HERE", "PUT-YOUR-JS-SECRET-KEY-HERE", "v1");
Try the following once you run the application:
Below you will find some of the examples of using the Backendless API in the application:
$('document').ready( function() { // bootstrap & render App App.store = {}; App.store.invoices = Backendless.Persistence.of(function invoice(){}); try { renderApp(App.store.invoices.find( { options: { related: ["items"] } }).data ); } catch(e) { renderApp( [] ); } ...
Line 5 obtains a reference to the “invoices” data store in Backendless. The returned object provides access to the CRUD (Create, Retrieve, Update, Delete) operations for that table.
Line 8 (find) sends a request to load all the previously saved invoice objects.
Lines 10-13 request that the invoice objects returned by Backendless included references to the related “items” objects (an Invoice contains line items or just “items”).
var handleInvoiceSave = function(properties) { try{ var obj = App.store.invoices.find({ options:{ related: ["items"] }, condition: "id='" + properties.id +"'" }).data[0]; if(obj){ properties.objectId = obj["__updated__objectId"] || obj.objectId; for(var i = 0; i < obj.items.length; i++){ for(var j = 0; j < properties.items.length; j++){ if(properties.items[j].id == obj.items[i].id){ properties.items[j].objectId = obj.items[i].objectId; } } } } } catch(e){ }finally{ App.store.invoices.save(properties); } }
Lines 3-7: check if the invoice has been previously saved. Uses the “condition” parameter where it specifies to search for the invoice by the “id” property.
Lines 10-19: if the invoice is found (i.e. it has been previously saved), iterate through the items and assign the item’s “objectId”. In this example, each “item” has an “id” assigned on the client-side (/shared/js/invoice.js, lines 14 and 28). On top of this, Backendless assigns its own ID to each saved object. That ID is stored in the “objectId” property. It is important to maintain consistency between the objects by correlating the IDs. This block of code accomplishes it for the save operation.
Line 22: once the IDs are assigned, the entire invoice (with all the items) is saved.
var handleInvoiceDelete = function(properties) { console.log("delete invoice"); App.store.invoices.remove( properties, new Backendless.Async(function(){ })); }
var handleSignUp = function(inputs) { var user = new Backendless.User(); user.login = inputs.username; user.email = inputs.email; user.password = inputs.password; Backendless.UserService.register( user, new Backendless.Async( function(){ App.hideModalForm() }, function(data){ App.renderModalFormError({error: data.message}); })); };
Lines 2-5: Create a Backendless.User object which contains the values for all the user properties defined in step 7 above.
Lines 6-11: Send a request to Backendless to register the user. The request is asynchronous with the Backendless.Async object handling the callbacks for success and error functions.
var handleSignIn = function(inputs) { Backendless.UserService.login( inputs.username, inputs.password, new Backendless.Async( function(data){ App.user = new Backendless.User(data); App.hideModalForm(); App.renderUserSignedIn(data); },function(data){ App.renderUserAuthenticationError(); App.renderModalFormError({error: data.message}); }) ); };
Line 2: Send a login request to Backendless. The first argument must be a value for the property defined as “Identity” (see step 7 above).