Introduction
This article seeks to demonstrate how one can create a CRUD web app using JQuery Mobile and XML single file record as a backend for storing your records. I will assume a very simple library system where one will store book details. These will be Title, Author and ISBN for each book available.
The app itself will list available stored books by reading aand listing each book, have functionality to add a book, update it and also delete it.
The principles applied are are the same as in this article, however due to using XML as a backend, some tweaks have been done on the code to create and also read such files. These include adding javascript files within the app to convert xml to json and also convert json to xml, xml2json.js and json2xml.js respectively.
The xml files used as the backend are just basic files, where each record is stored inside <modelname> attribute.
Some silly assumptions: You are familiar with my article JQuery Mobile & JSON. The structure of the source code is the same as we are also using Ajax calls to PHP files to read, update and delete records from the database, however this case around its not json files but xml files. I'm assuming that you are also familiar with JQuery Mobile HTML definitions for UI creation.
By the way, the xml2json.js is a JQuery plugin that converts your xml to a json object. As its easy to manipulate json objects inside our app I apted for this approach. This was obtained here. This is used when reading each record in my app.
json2xml.js is used when saving my xml records. You will recall from my previous CRUD apps that I set screen contents entered by a user to a json object and save this object to a chosen backend. So this script basically does that, takes my json objects and converts it to xml so that I can save it as such. This script was obtained here.
Download LibraryXML.zip
Background
For the past couple of weeks, I have discussing creating CRUD apps with JQuery Mobile for the various backends. You can view my articles here for more clarity. The approach I will follow here is the same. My applications are just for simple CRUD operations and they just provide basic operations. At the end of this exercise, we want to habe an application that looks like this.
Figure 1: Springboard (the main menu of our JQuery Mobile Library App)
![Image 1](/KB/mobile/894983/springboard-r-700.png)
![Image 2](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Figure 2: Book Listing (listview listing of all books recorded in our app)
![Image 3](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Figure 3: Add Book (screen to add a book to the library)
![Image 4](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Figure 4: Update/Delete Book (screen to update or delete book details)
![Image 5](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Figure 5: Book Report (table widget listing all books in our library)
![Image 6](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Figure 6: Book Report - Excel (an excel report of our Library)
![Image 7](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
I will delve on the CRUDV operations here as you can refer to my previous articles for other sections of this article like, reports, exporting to excel etc.
Using the code
CR - eating Books
The books created and record with the app will be stored on a folder on your server called Book. This is based on the model name we have defined. The title of each book is the primary key for each book and the xml file name will then be a cleaned version of the book title with a .xml extension.
Add Book: HTML Definition:
<div data-model="Book" id="pgAddBook" data-role="page">
<div data-position="left" data-display="reveal" data-position-fixed="true" id="pgAddBookPnl" data-role="panel">
<ul data-role="listview" id="pgAddBookPnlLV">
<li data-icon="plus"><a data-transition="slide" href="#pgAddBook">New</a></li>
<li data-icon="eye"><a data-transition="slide" href="#pgRptBook">Report</a></li>
<li data-icon="carat-l"><a data-transition="slide" href="#pgBook">Back</a></li>
</ul>
</div>
<header id="pgAddBookHdr" data-role="header" data-position="fixed">
<h1>Library</h1>
<a data-role="button" id="pgAddBookMenu" href="#pgAddBookPnl" data-icon="bars" class="ui-btn-left">Menu</a>
</header>
<div id="pgAddBookCnt" data-role="content">
<h3>Add Book</h3><form action="#" method="post" id="pgAddBookForm" name="pgAddBookForm">
<div data-role="fieldcontain">
<label for="pgAddBookTitle">Title<span style='color:red;'>*</span></label>
<input required title="Enter title here." type="text" name="pgAddBookTitle" id="pgAddBookTitle" placeholder="Enter title here." autocomplete="off" data-clear-btn="true"></input>
</div>
<div data-role="fieldcontain">
<label for="pgAddBookAuthor">Author<span style='color:red;'>*</span></label>
<input required title="Enter author here." type="text" name="pgAddBookAuthor" id="pgAddBookAuthor" placeholder="Enter author here." autocomplete="off" data-clear-btn="true"></input>
</div>
<div data-role="fieldcontain">
<label for="pgAddBookISBN">ISBN<span style='color:red;'>*</span></label>
<input required title="Enter isbn here." type="text" name="pgAddBookISBN" id="pgAddBookISBN" placeholder="Enter isbn here." autocomplete="off" data-clear-btn="true"></input>
</div>
</form>
</div>
<footer id="pgAddBookFtr" data-role="footer" data-position="fixed">
<div id="pgAddBookFtrNavBar" data-role="navbar">
<ul>
<li><a id="pgAddBookBack" data-icon="carat-l">Cancel</a>
</li>
<li><a type="submit" id="pgAddBookSave" data-icon="action">Save</a>
</li>
</ul>
</div>
</footer></div>
We are just using three input controls for the books. The screen has a cancel button to take a user back to the book listing and a save button.
Add Book: Save button click event
$('#pgAddBookSave').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var BookRec = pgAddBookGetRec();
app.addBook(BookRec);
});
The details of the book entered as read and stored as BookRec by pgAddBookGetRec()
function pgAddBookGetRec() {
var BookRec = {};
BookRec.Title = $('#pgAddBookTitle').val().trim();
BookRec.Author = $('#pgAddBookAuthor').val().trim();
BookRec.ISBN = $('#pgAddBookISBN').val().trim();
return BookRec;
}
and app.addBook(BookRec); is called, this function being passed the json record of the book.
app.addBook = function (BookRec) {
var Title = BookRec.Title;
Title = Title.split(' ').join('-');
BookRec.Title = Title;
var recordXML = json2xml(BookRec, "Book");
recordXML = "<?xml version='1.0' encoding='utf-8'?>" + recordXML;
var req = Ajax("xmlSaveBook.php", "POST" , recordXML);
if (req.status == 200) {
toastr.success('Book record saved.', 'Library');
var pgFrom = $('#pgAddBook').data('from');
switch (pgFrom) {
case "pgSignIn":
$.mobile.changePage('#pgSignIn', {transition: pgtransition});
break;
default:
pgAddBookClear();
}
} else {
toastr.error('Book record not saved. Please try again.', 'Library');
}
};
The book title is cleaned to remove any spaces and these are converted to -. Then the contents of the entered book are converted from this json object to an xml string..
var recordXML = json2xml(BookRec, "Book");
Then this book xml record is formatted property to have a xml header.
recordXML = "<?xml version='1.0' encoding='utf-8'?>" + recordXML;
Then a POST ajax call is made, thus saving the book record as an xml file to the server Book folder using the book title.
var req = Ajax("xmlSaveBook.php", "POST" , recordXML);
then depending on the success of the call we tell the end user in a toast. Looking at xmlSaveBook.php, this is what happens:
<?php
$record = file_get_contents('php://input');
$xmlrec = new SimpleXMLElement($record);
$Title = $xmlrec->Title;
if (!is_dir('./Book/')) {
mkdir('./Book/');
}
$xmlFile = "Book/" . $Title . ".xml";
$f = fopen($xmlFile, 'w') or die("Error: Can't open file. Got write permission?");
fwrite($f, $record);
fclose($f);
?>
This gets the xml contents passed to the server and uses SimpleXMLElement to parse it inside the php file. The title of the book is read then if the Book directory in the server does not exist, its created. The xmlFile is then defined to include the whole path and then the contents of the xml record saved to file.
The Ajax function is stored within the remoteserver.js file included and is depicted below:
function Ajax(URL, method, data, callback) {
if (typeof(method) !== 'object') {
var settings = new Object;
if(!method || method === null || typeof(method) === 'undefined') method = "GET";
settings.type = method.toUpperCase()
if(!data || data === null || typeof(data) === 'undefined') data = "";
settings.data = data;
if (!callback) {
settings.async = false;
} else {
settings.success = callback;
settings.fail = callback}
}
return $.ajax(URL, settings);
}
U - pdating Books
Updating a book takes one selecting a book from available book list and then an edit screen appears. One can then update the book details, with the exception of the book title and clicking Update.
Update Book: HTML Definition
<div data-url="Title" data-model="Book" id="pgEditBook" data-role="page">
<div data-position="left" data-display="reveal" data-position-fixed="true" id="pgEditBookPnl" data-role="panel">
<ul data-role="listview" id="pgEditBookPnlLV">
<li data-icon="plus"><a data-transition="slide" href="#pgAddBook">New</a></li>
<li data-icon="eye"><a data-transition="slide" href="#pgRptBook">Report</a></li>
<li data-icon="carat-l"><a data-transition="slide" href="#pgBook">Back</a></li>
</ul>
</div>
<header id="pgEditBookHdr" data-role="header" data-position="fixed">
<h1>Library</h1>
<a data-role="button" id="pgEditBookMenu" href="#pgEditBookPnl" data-icon="bars" class="ui-btn-left">Menu</a>
</header>
<div id="pgEditBookCnt" data-role="content">
<h3>Edit Book</h3><form action="#" method="post" id="pgEditBookForm" name="pgEditBookForm">
<div data-role="fieldcontain">
<label for="pgEditBookTitle">Title<span style='color:red;'>*</span></label>
<input required readonly="readonly" data-clear-btn="true" autofocus="true" title="Enter title here." type="text" name="pgEditBookTitle" id="pgEditBookTitle" placeholder="Enter title here." autocomplete="off"></input>
</div>
<div data-role="fieldcontain">
<label for="pgEditBookAuthor">Author<span style='color:red;'>*</span></label>
<input required title="Enter author here." type="text" name="pgEditBookAuthor" id="pgEditBookAuthor" placeholder="Enter author here." autocomplete="off" data-clear-btn="true"></input>
</div>
<div data-role="fieldcontain">
<label for="pgEditBookISBN">ISBN<span style='color:red;'>*</span></label>
<input required title="Enter isbn here." type="text" name="pgEditBookISBN" id="pgEditBookISBN" placeholder="Enter isbn here." autocomplete="off" data-clear-btn="true"></input>
</div>
</form>
</div>
<footer id="pgEditBookFtr" data-role="footer" data-position="fixed">
<div id="pgEditBookFtrNavBar" data-role="navbar">
<ul>
<li><a data-transition="slide" id="pgEditBookBack" href="#pgBook" data-icon="carat-l">Cancel</a>
</li>
<li><a type="submit" id="pgEditBookUpdate" data-icon="action">Update</a>
</li>
<li><a id="pgEditBookDelete" data-icon="delete">Delete</a>
</li>
</ul>
</div>
</footer></div>
The Update/Delete screen has Cancel, Update, Delete buttons at the footer to ensure that books are either updated or deleted. When a user opts to Update a book, the details are read from this html definition input properties for each book and then saved to a json object that is later saved to the server. Let's look at this.
Update Book: Update button click event
$('#pgEditBookUpdate').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var BookRec = pgEditBookGetRec();
app.updateBook(BookRec);
});
When the Update button is clicked, the details entered on the form are read by pgEditBookGetRec and assigned to BookRec and this is later passed to app.updateBook to save it to the server.
function pgEditBookGetRec() {
var BookRec = {};
BookRec.Title = $('#pgEditBookTitle').val().trim();
BookRec.Author = $('#pgEditBookAuthor').val().trim();
BookRec.ISBN = $('#pgEditBookISBN').val().trim();
return BookRec;
}
Our AddPage input controls were pgAddBookTitle and for the update page, these are pgEditBookTitle. We have used two screens for adding and updating to ensure easy maintenance of the code. Then app.updateBook is called passing the BookRec to it to save.
app.updateBook = function (BookRec) {
var Title = BookRec.Title;
Title = Title.split(' ').join('-');
BookRec.Title = Title;
var recordXML = json2xml(BookRec, "Book");
recordXML = "<?xml version='1.0' encoding='utf-8'?>" + recordXML;
var req = Ajax("xmlSaveBook.php", "POST" , recordXML);
if (req.status == 200) {
toastr.success('Book record updated.', 'Library');
pgEditBookClear();
$.mobile.changePage('#pgBook', {transition: pgtransition});
} else {
toastr.error('Book record not updated. Please try again.', 'Library');
}
};
Just like the methods above, the edit record is converted to xml and a header included and this a POST done to the server using the same xmlSaveBook.php that was used for adding records. Remember, the record has changed however the saving methodology hasnt changed, thus using the same php file. You will note too that within the attached zip file, there are only three php files, to save, to get and to delete.
D - deleting Books
From the book update screen, one can select Delete to delete a book.
![Image 8](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
When a user opts to delete a book, a prompt is availed to prompt the user if they really want to delete the book. Deleting the book from the server is an action that cannot be undone. The book title is read from the update screen and this is passed to a msgbox page.
Update Page: Delete button click event
$('#pgEditBookDelete').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var Title = $('#pgEditBookTitle').val().trim();
$('#msgboxheader h1').text('Confirm Delete');
$('#msgboxtitle').text(Title.split('-').join(' '));
$('#msgboxprompt').text('Are you sure that you want to delete this book? This action cannot be undone.');
$('#msgboxyes').data('method', 'deleteBook');
$('#msgboxno').data('method', 'editBook');
$('#msgboxyes').data('id', Title.split(' ').join('-'));
$('#msgboxno').data('id', Title.split(' ').join('-'));
$('#msgboxyes').data('topage', 'pgEditBook');
$('#msgboxno').data('topage', 'pgEditBook');
$.mobile.changePage('#msgbox', {transition: 'pop'});
});
This passed our msgbox attributes to a msgbox screen defined like this: a dialog pop up screen
<div data-dismissible="false" data-transition="pop" data-model="msgbox" id="msgbox" data-role="dialog">
<header id="msgboxHdr" data-role="header" data-position="fixed">
<h1>Confirm</h1>
</header>
<div id="msgboxCnt" data-role="content">
<div id="msgboxtitle">
</div>
<br><div id="msgboxprompt">
<p>Are you sure you want to delete this record?</p>
</div>
<br><div style="text-align: center;" id="msgboxbuttons" class="ui-grid-a">
<div class="ui-block-a">
<a data-method="" data-id="" data-topage="" id="msgboxyes" data-role="button" data-icon="check">Yes</a>
</div>
<div class="ui-block-b">
<a data-method="" data-id="" data-topage="" id="msgboxno" data-role="button" data-icon="delete" data-theme="b">No</a>
</div>
</div>
</div>
</div>
My previous articles have discussed this msgbox approach in detail, you can refer to that, however, when the Yes button is clicked, which was defined with
$('#msgboxyes').data('method', 'deleteBook');
The app.deleteBook method is fired, passing the id of the book saved like this:
$('#msgboxyes').data('id', Title.split(' ').join('-'));
MsgBox: Yes button click event
$('#msgboxyes').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
var yesmethod = $('#msgboxyes').data('method');
var yesid = $('#msgboxyes').data('id');
app[yesmethod](yesid);
});
yes button reads the passed data attribute of the method and the id of the record to delete and then calls
app[yesmethod](yesid);
to delete the record. Let's look at the app.deleteBook function.
app.deleteBook = function (Title) {
Title = Title.split(' ').join('-');
var req = Ajax("xmlDeleteBook.php/?Title=" + Title);
if (req.status == 200) {
toastr.success('Book record deleted.', 'Library');
} else {
toastr.error('Book record not deleted.', 'Library');
}
$.mobile.changePage('#pgBook', {transition: pgtransition});
};
This cleans the book title and calls xmlDeleteBook.php, passing it the title of the book. If you notice, the extension of the book record is not done here. When the book is deleted, the user is told by a toast.
xmlDeleteBook.php's insides:
<?php
$Title = $_GET['Title'];
unlink('./Book/'.$Title.'.xml');
?>
This gets the passed book title, then deletes the file with the complete path using the unlink php method. That concludes our XML CRUD operations, let's look at getting and listing all the books in the listview.
V - iewing Books
Getting all available books and getting a single book from the server uses xmlGetBook.php. This looks like this:
<?php
If (isset($_REQUEST['file'])) {
$file = basename($_REQUEST['file']);
echo file_get_contents('./Book/'.$file);
} Else {
If (is_dir('./Book') && $handle = opendir('./Book/')) {
While (False !== ($entry = readdir($handle))) {
If (!is_dir($entry)) {
echo basename($entry)."\n";
}
}
closedir($handle);
} Else {
header("HTTP/1.0 404 Not Found");
}
}
?>
When an Ajax() call is made without a file arguement, all the files in the folder are returned delimited by a CRLF, i.e. \n. These are then extracted and listed on the listview on runtime. When the file name is specified, the individual file is read. Let's look at this in detail.
Book Listing: HTML Definition
<div data-model="Book" id="pgBook" data-role="page">
<div data-position="left" data-display="reveal" data-position-fixed="true" id="pgBookPnl" data-role="panel">
<ul data-role="listview" id="pgBookPnlLV">
<li data-icon="plus"><a data-transition="slide" href="#pgAddBook">New</a></li>
<li data-icon="eye"><a data-transition="slide" href="#pgRptBook">Report</a></li>
<li data-icon="carat-l"><a data-transition="slide" href="#pgMenu">Back</a></li>
</ul>
</div>
<header id="pgBookHdr" data-role="header" data-position="fixed">
<h1>Library</h1>
<a data-role="button" id="pgBookMenu" href="#pgBookPnl" data-icon="bars" data-transition="slide" class="ui-btn-left">Menu</a>
<a data-role="button" id="pgBookNew" data-icon="plus" data-theme="b" class="ui-btn-right">New</a>
</header>
<div id="pgBookCnt" data-role="content">
<h3>Books</h3><ul data-role="listview" data-inset="true" id="pgBookList" data-filter="true" data-filter-placeholder="Search Books">
<li data-role="list-divider">Your Books</li>
<li id="noBook">You have no books</li>
</ul>
</div>
</div>
This above defines the listview page that lists all available books in the library. The name of the listview is pgBookList. This listview is updated at runtime and is thus clickable to ensure that when each book is selected by the user and update screen will be opened by the app. Before the book listing page is shown, the web apps runs some operations.
app.BookBindings = function () {
$(document).on('pagebeforechange', function (e, data) {
var toPage = data.toPage[0].id;
switch (toPage) {
case 'pgBook':
$('#pgRptBookBack').data('from', 'pgBook');
app.checkForBookStorage();
break;
In this case, app.checkforBookStorage. This is defined like this.
app.checkForBookStorage = function () {
var BookObj = app.getBook();
if (!$.isEmptyObject(BookObj)) {
app.displayBook(BookObj);
} else {
$('#pgBookList').html(BookHdr + noBook).listview('refresh');
}
};
This method calls a method that is used a lot within the app called app.getBook(). Whatever is executed by that method, it gets stored in variable BookObj. This BookObj is then checked if its empty or not, if empty, the listview will show no records, however, if there are records, method app.displayBook will be called passing the BookObj.
app.getBook = function () {
var BookObj = {};
var icnt, itot;
var req = Ajax("xmlGetBook.php");
if (req.status == 200) {
var recFiles = req.responseText;
recFiles = recFiles.split('\n');
itot = recFiles.length - 1;
for (icnt = 0; icnt <= itot; icnt++) {
var recFile = recFiles[icnt];
if (recFile.length > 0) {
var req = Ajax("xmlGetBook.php?file=" + encodeURIComponent(recFile));
if (req.status == 200) {
var BookRec = $.xml2json(req.responseText);
var Title = BookRec.Title;
Title = Title.split('-').join(' ');
BookRec.Title = Title
BookObj[Title] = BookRec;
}
}
}
var keys = Object.keys(BookObj);
keys.sort();
var sortedObject = Object();
var i;
for (i in keys) {
key = keys[i];
sortedObject[key] = BookObj[key];
}
BookObj = sortedObject;
return BookObj;
}
};
As noted above, app.getBook calls xmlGetBook.php first without passing the file attribute. This returns all available files in the Book folder of the server for this app. This is returned as responseText. This is then parsed with the CRLF characters specified and then another ajax call is made to read each file, now passing the file name.
First method:
var req = Ajax("xmlGetBook.php");
Second method:
var req = Ajax("xmlGetBook.php?file=" + encodeURIComponent(recFile));
Then for each book record found, the BookObj is updated and then this is sorted by book title and returned to be what is eventually passed to app.displayBook.
BookObj[Title] = BookRec; (updates of the BookObj)
return BookObj; (return of the BookObj to be passed for display)
app.displayBook, receives all the books read from the server and displays them to the listview like this:
app.displayBook = function (BookObj) {
var html = '';
var n;
for (n in BookObj) {
var BookRec = BookObj[n];
var pkey = BookRec.Title;
pkey = pkey.split('-').join(' ');
BookRec.Title = pkey;
var nItem = BookLi;
nItem = nItem.replace(/Z2/g,n);
var nTitle = '';
nTitle = n.split('-').join(' ');
nItem = nItem.replace(/Z1/g,nTitle);
var nDescription = '';
nDescription += BookRec.Author;
nDescription += ', ';
nDescription += BookRec.ISBN;
nItem = nItem.replace(/DESCRIPTION/g,nDescription);
html += nItem;
}
$('#pgBookList').html(BookHdr + html).listview('refresh');
};
As you noted in the listing screen, we want to show the Author and ISBN in the description of each book. For each book read, these properties are then read and then the listview item updated and a single update to the listview done. This helps in speeding the DOM manipulation.
Book Table Report: HTML Definition
The book table report is initially blank and fed with the book list at runtime. This is defined like this.
<div data-model="Book" id="pgRptBook" data-role="page">
<header id="pgRptBookHdr" data-role="header" data-position="fixed">
<h1>Library</h1>
<a data-role="button" id="pgRptBookBack" data-icon="carat-l" class="ui-btn-left">Back</a>
<a data-role="button" id="pgRptBookNew" href="#pgAddBook" data-icon="plus" data-theme="b" data-transition="slide" class="ui-btn-right">New</a>
</header>
<div id="pgRptBookCnt" data-role="content">
<table id="RptBook" data-column-btn-text="Columns To Display" data-column-btn-theme="b" data-role="table" data-mode="columntoggle" data-column-popup-theme="a" class="ui-responsive table-stroke table-stripe ui-shadow">
<caption>Books Report</caption>
<thead>
<tr class="ui-bar-a">
<th class="ui-bar-a">Title</th>
<th data-priority="2" class="ui-bar-a">Author</th>
<th data-priority="3" class="ui-bar-a">ISBN</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr><td></td></tr>
<tr><td colspan="3">Powered by JQM.Show - https://play.google.com/store/apps/details?id=com.b4a.JQMShow</td></tr></tfoot>
</table>
<div data-role="fieldcontain">
<a download="Book.xls" onclick="return ExcellentExport.excel(this, 'RptBook', 'Book');" id="pgRptBookExport" data-corners="true" href="#" class="ui-btn ui-corner-all ui-shadow">Export to Excel</a></div>
</div>
</div>
The table is also generated during runtime by executing the app.getBook method discussed above and then looping through each book and generating a table row as depicted below. This is then fed to the table as defined in the html above.
app.BookRpt = function () {
$('#RptBook tbody tr').remove();
var BookObj = app.getBook();
var newrows = '';
var n;
for (n in BookObj) {
var BookRec = BookObj[n];
n = n.split('-').join(' ');
var eachrow = '<tr>';
eachrow += '<td class="ui-body-c">' + n + '</td>';
eachrow += '<td class="ui-body-c">' + BookRec.Author + '</td>';
eachrow += '<td class="ui-body-c">' + BookRec.ISBN + '</td>';
eachrow += '</tr>';
newrows += eachrow;
}
$('#RptBook').append(newrows);
$('#RptBook').table('refresh');
};
Also here to speed DOM manipulation, the table is updated once after all the rows have been generated by appending eachrow to newrows.
That concludes our crucial points about this article. Enjoy.
Points of Interest
A previous article discussed how we can create a JQuery Mobile web apps using JSON single records as a backend. This seeked to follow the same approach but use XML as back end records. The manipulation of the xml files with the existence of the two libraries, xml2json and json2xml, it has made it both possible and easy for making this possible and I pass credits to the teams who worked on those two scripts.
The SimpleXMLElement PHP class also proved helpful in manipulation XML inside the php file to get the book title. This has helped my exposure to the power of PHP.
I'm a Bachelor of Commerce graduate, fell inlove with ICT years back with VB5. Used Pick & System Builder to create a windows app. Very curious, developed my first web database app called Project.Show using ExtJS. Published on Google Play Store, learned JQuery Mobile, a project manager at best. My first intranet app eFas with MySQL.
Fear closes people to a lot of things and we hold ourselves back being held by it. Thus the sooner you believe you can't do something, the sooner everything will work towards that belief. Believe in yourself at all times because you can do anything you set your mind to it!
I have a very beautiful woman and four kids, the best joys in the world. East London, South Africa is currently home.
Awards:
Best Mobile Article of February 2015 (First Prize)
http://www.codeproject.com/Articles/880508/Create-a-CRUD-web-app-using-JQuery-Mobile-and-Loca
Best Mobile Article of May 2015 (Second Prize)
http://www.codeproject.com/Articles/991974/Creating-JQuery-Mobile-CRUD-Apps-using-JQM-Show-Ge
Apps
Bible.Show (Android Store App)
https://www.facebook.com/bibleshow
https://play.google.com/store/apps/details?id=com.b4a.BibleShow
JQM.Show (Android Store App)
https://www.facebook.com/jqmshow
https://play.google.com/store/apps/details?id=com.b4a.JQMShow
CodeProject.Show (An offline CodeProject Article writer)
http://www.codeproject.com/Articles/993453/CodeProject-Show-A-CodeProject-offline-article-wri