RhoElements - Building Your First App - Part 5 Saving Scan Data
In the of this , we created javascript functions to create the database and associated tables we will be using. We also loaded the Developer Conference session data into the table. In this part of the series, we will basically complete the functionality of the application. Before we get into saving the scan data, let's first load the breakout session data into a drop down so the user can select the presentation that they will be scanning attendees for.
Let's open up the index.html file and replace our placeholder inside the selector div section with a
As you can see we created a disabled option as a placeholder and indicated that it should call a javascript function sessionChange(). Before we create the create the sessionChange function let's create a function, loadSessionSelect() to load more options on page load:
function loadSessionSelect() { //load session Select with data var sessionList=document.getElementById("session"); for (i=0;i { eventSession = eventData[i] var option=document.createElement("option"); option.text=eventSession.title; option.value=i; // Put index here not sessionID so we don;t have to do DB call to get session info sessionList.add(option); } } |
and the modify the onPageLoad function to call loadSessionSelect():
Let's test loading the index.html file now, but instead of loading it on the device - let's load it inside of Google Chrome browser. Yup, you heard me right, Google's Chrome Browser. Chrome, Safari and other browsers that are based on webkit will respond very similar to pages loaded inside of RhoElements. Drag your file over to Chrome to load the index.html.
What happened you say? Well let's turn on Chrome's very useful develoepr tools by pressing CTRL-SHIFT-I (Or Tools/Developer Tools from the menu). You should see a javascript error indicated in the lower right hand corner. Click on it and you will see it indicating that generic is not defined. This is because on your desktop, the RhoElements plugin is not recognized by Chrome. "generic", if you recall if what we used in the database file for writing out to the log file when an error happened during the database transaction.
But that does not mean that you can't use your desktop browser to help you develop a RhoElements application. In fact Chrome is very useful for this task. I will do a deep dive on this topic at a later time, but for now let us put in some simple code to detect if we are running inside RhoElements.
Let us add a variable to the top of our javascript called isRhoElements and set it to false.Now let's add the following snippet to the beginning of the onPageLoad function that will check to see if we are using RhoElements:
RhoElements will include a string MotorolaWebKit inside of the User Agent string. So we can use this as a mechanism to check to see if the app is running inside of RhoElements. Now that we will have a variable accessible from any of our javascript, let's go back into the db.js file and modify the onError function:
Refresh Chrome browser and you will no longer see any Javascript errors.
If you click on the Resources tab inside Chrome Browser's Developer Tools you will also Databases listed. If you click through you will see that the database EventTracker has been created with two tables. If you click on the eventSessions table you will see the records that we inserted from the code in the
Ok so we are almost there. Before we create the code to insert scan data into the sessionAttendees table, we need to create that sessionChange() function that the drop-down will call after the user changes the selected presentation that they will be scanning attendees for. For this I am going to introduce another HTML5 concept called session storage. Session storage is like an enhanced type of 'cookie'. It let's you create name/value pairs and have your application in control of them and not the browser. We will be using the localStorage object with methods .setItem(name,value) and .getItem(name).
In the onPageLoad function lets create a localStorage item called sID -this will contain the actual sessionID that is selected:
Now let's create the sessionChange() and put in a similar statement so that the selected value is stored in the sID localstorage variable.We will also add some code to enable the scanner now that as session has been selected and also some code to display the Event Session Data into the sessionDetail DIV. By the way, these localStorage variables, like the WebSQL is persistant across sessions as well as device reboots, etc.
function sessionChange() { sessionIndex = document.getElementById('session').value; //remember what localStorage.setItem('sID',eventData[sessionIndex].sessionId); //Display Session Detail var sDetail = document.getElementById('sessionInfo'); sDetail.innerHTML = eventData[sessionIndex].title + '
//Enable the scanner if(isRhoElements) { //enable scanner since a session was selected - ok if already enabled enableScanner();
} } |
Now let's save everything and refresh the index.html inside of Chrome Browser. Choose an option from the drop down and you will not only see the details displayed inside the sessionDetail DIV, but if you still have the Chrome Developer tools open, you will see the Local Storage variable sID change every time you select a new option (don't forgot to click the refresh icon in the developer tools to see the current value):
Ok let's work on one of the final steps to make this application completely functional. In this section we will process and store the scanned in data. Recall that the actual barcode data we will be expecting is in the form of vCard format. You can google the specific format of vCard and you will see that various fields that can be in it. Since this is our Developers conference we know what fields will be in the vCard object. For the application I just want to display the attendee name and company and store the complete vCard raw data into the database so that it could possibly used at a later time.
First I created a simple function to allow me to extract certain vCard fields. So I created a generic function that I will pass in the full vCard object and a fieldname. If the vCard fieldname is found, I will return the string after the name. For the attendee's name I will use the FN vCard field and for the attendee's company I will use the ORG field: (I am sure there is a more robust Javascript vCard library out there but this works for my simple app). You can store this function in any of your linked JS files, but I decided to put it in the DB.js file
function getVcardInfo(vCard,fieldName) { lines = vCard.split('\n'); returnValue = ''; for (n in lines) { line = lines[n];
var results = line.split(':'); key = results[0].toLowerCase(); value = results[1]; if(fieldName.toLowerCase() == key) { returnValue = value; break; } if(n==lines.length-1) break; } return returnValue; } |
Now lets go back to the DIV placeholders and add one more to keep track of the number of people scanned for each session.
Let's modify the doScan() and call a function dbInsertScanData() to insert the record and update the display to show a new attendee count and the persons name and company.
function dbInsertScanData( scanData) { sessionId = localStorage.getItem('sID'); db.transaction( function(tx) { tx.executeSql("INSERT INTO sessionAttendees ( SessionId,ScannedData) VALUES (?,?)", [ sessionId, scanData], function(tx, result) { //Clear Last Scanned var attendeeCount = document.getElementById('attendeeCount'); attendeeCount.innerHTML = parseInt(attendeeCount.innerHTML) + 1; var attendeeName=document.getElementById('scanInfo'); attendeeName.innerHTML = getVcardInfo(scanData,'fn') + " }, onError ); } ); } |
Notice that I am calling the localStorage.getItem method to retrieve the sessionID that will be stored in the database. The Insert statement looks very similar to the one we did earlier, but this time we are inserting into the sessionAttendees table and passing in two parameters. The other lines of code are updating the attendeeCount that is displayed as well as the information from the vCard object for the attendee that was scanned.
Before I test this with an actual device, I will create a simple test function and hook it to a temporary button's onClick event so I can check to make sure this is working.
function testScan() { var $vcardSample = 'BEGIN:VCARD\nVERSION:2.1\nN:Galvin;Robert\nFN:Rob Galvin\nORG:Motorola Solutions Inc\nEMAIL:rob.galvin@motorolasolutions.com\nEND:VCARD\n'; dbInsertScanData($vcardSample); } |
After saving all and refreshing in Chrome Browser, I can see the test data being displayed and the information being saved in the database.
Now we have the application working quite well by now. Let's move it to the device and test it from there with the actual scanner.Notice that the scanner is not enabled when the page loads, but only after a session has been selected from the list.
If you check the database file on the device again like we did in the you will see that these records you are scanning are indeed making it into the database on the device.
One last optional thing to do is to add a button that will allow the user to exit the application. After doing that and editing the config.xml to turn off debug mode. I have an Event Attendee appliication that is fully functional.
Well the application is functional and so far we covered the following topics:
- Using Chrome Developer Tools to help with debugging and application testing
- Using localStorage to store name/value pairs
- Handling data from scanning a QR Code bar code and storing in the WebSQL database
It may not be the prettiest looking application, but I will leave that creativity to you. along with a final stylized result. Stay tuned for further blog entries on other related topics including how you would make this application work in a casually connected environment. Be sure to leave me some comments to let me know how useful this was.
Robert Galvin