HTML5: Local Storage and Offline Applications in Depth

HTML5: Local Storage and Offline Applications in Depth

with Bill Weinman

 


This course describes how to save application data such as preferences or form data in the client's browser and use it in applications, including those run offline. Author and programmer Bill Weinman covers the various local storage options provided in HTML5, including local storage, session storage, and the Web SQL and Indexed Database APIs, with practical examples that show how to create and maintain a database in each scenario. The course also covers the use of storage events for change tracking and the cache manifest for using web applications offline.
Topics include:
  • Understanding storage components of the HTML5 architecture
  • Providing client-side storage
  • Understanding the Storage() interface
  • Keeping context with sessionStorage
  • Understanding the Web SQL and Indexed Database APIs
  • Creating a local storage database
  • Reading, writing, editing, and deleting storage data
  • Handling storage events with local storage
  • Running applications offline

show more

author
Bill Weinman
subject
Developer, Web, Web Development
software
HTML
level
Intermediate
duration
2h 23m
released
Jun 01, 2011

Share this course

Ready to join? subscribe


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:03Hi! I am Bill Weinman and I would like to welcome you to HTML5: Local Storage and
00:08Offline Applications in Depth.
00:11In this course, we will be examining the four storage options available in HTML5:
00:16local storage, session storage, WebSQL, and IndexedDB.
00:21I will show you how to create a local dataset using each of these
00:24technologies, how to read from your datasets, how to update them, and how to
00:28delete data from them, creating a complete application that provides these four
00:33fundamental capabilities using each of the available local storage options
00:37provided with HTML5.
00:40Along the way, we will look at storage events, so that separate windows can
00:43update each other in the same application and the offline applications
00:47interface so that your applications can continue to run even when not connected to the network.
00:53If you need to understand the storage options available with HTML5 and put them
00:58to work in your applications or for your clients, then you will get the answers
01:02you need in HTML5; Local Storage and Offline Applications in Depth.
Collapse this transcript
Using the exercise files
00:00Here in the Exercise Files folder, you will find folders for each of the
00:04chapters in the tutorial.
00:06The files inside the folders are generally organized by movie number with -start
00:12and -done files for each of the exercises.
00:15You want to start with a working copy of the start file and work with the copy,
00:21so that you can start over again with a fresh copy if you need to.
00:26In the CSS folder, you will find a simple CSS file that is used for all of the examples.
00:33I am going to open this in my editor and show you what's in this file.
00:39This CSS file is used in all of the exercises.
00:44In the Javascript folder, you will find a small JavaScript library called
00:49bwH5LS.js and this is used to display the result tables in each of the examples.
Collapse this transcript
Using the JavaScript library included with the exercise files
Collapse this transcript
Using the custom CSS included with the exercise files
Collapse this transcript
1. Overview
Four types of storage
00:00HTML5 provides four different types of storage for storing data locally on a user's machine.
00:06These are local storage, session storage, Web SQL and IndexedDB.
00:10We will cover each of these individually in a moment.
00:12Some of these storage types have their own purposes, others are the result of
00:16fragmentation, and none of these techniques will work in older browsers.
00:20We will start by discussing local storage and session storage together, because
00:24they are closely related.
00:26Local storage and session storage are sometimes called web storage or DOM
00:32storage, DOM standing for Document Object Model.
00:35This is the common application programming interface for webpages.
00:38You can think of local storage and session storage as an improvement over cookies.
00:43They're not designed for large amounts of data. They are limited in size to 5 to
00:4710 MB, depending on the implementation, and they store the data locally on the
00:52client and they don't automatically send their data to the server as cookies do.
00:57The local storage version is the persistent storage version.
01:00This is the version that you will use the most.
01:02This is like persistent cookies that might have an expiration set in them, and
01:06the session storage version is transient.
01:08That's designed to go away when you close a window.
01:11Both of these specifications use the same object interface in JavaScript and
01:15that's called Storage and they are supported by all the major browsers in
01:20their latest versions.
01:22The Web SQL Storage specification is where things start to fragment.
01:27Web SQL Storage is a fully relational SQL interface to a relational database
01:35engine that stores data locally on the user's machine.
01:39All the implementations that implement Web SQL use the SQLite3 database engine.
01:45That's because it's really the only freely available database that's out there
01:50that will do what needs to be done for the specifications.
01:54It's a fully self-contained SQL engine that stores all of the data in one file
02:00and the entire engine lives in a driver and so is perfectly suited to this
02:04type of an application.
02:06So, this is both the strength and the Achilles' heel of this implementation.
02:10The problem is that because SQLite is the only suitable database engine for this
02:16purpose, all the implementations use SQLite and that might not seem like a problem.
02:20It seems like it would make things very easy and cross platform.
02:24But the World Wide Web Consortium considered it a bad idea to standardize on one
02:28dialect of SQL, and since no SQL engine really follows the standard completely,
02:34the standard doesn't define a complete set of SQL.
02:38The argument goes that they would have to then define a subset of SQL and they
02:42didn't want to have to do that based on one SQL engine.
02:45Of course, by this same argument, they would have to abandon JavaScript, but I
02:49don't think they're thinking like that.
02:51So, Web SQL uses the SQLite3 engine for its storage in all implementations and
02:58it's supported in Safari, Chrome, Opera, Android, iOS, and it is not going to be
03:05supported in IE or Firefox.
03:07Both Microsoft and the Mozilla people have said that they're not going to
03:11support it in the future.
03:13So this means that there's really no clear cross-platform solution for a
03:17database-scale local storage.
03:19The other proposal is something called Indexed Database storage, more
03:23commonly called IndexedDB.
03:25This uses a key value model that's not a relational database.
03:29It simply stores values and hierarchical objects, and like Web SQL Storage,
03:35IndexedDB has fragmented support from the browser and vendor as well.
03:39As of today, it's only supported in Firefox, Microsoft plans to support it in
03:43the future in IE 10, which they have said should come out within a year as of
03:48this writing, which is in early 2011.
03:51And Google has said they will support it in Chrome 11. Apple is going to
03:54support it in Safari 6.
03:56None of these implementations are available today.
03:58The only one that's available today is Firefox 4.
04:02So, that means that there is no clear cross browser solution for database
04:07scale local storage.
04:09So, you can see there are a number of different local storage solutions and
04:12there is some fragmentation in the implementations.
04:15At this point, it's fairly safe to use the local and session storage options,
04:20but Web SQL and IndexedDB are fragmented, and either one may not be supported in
04:24a given common browser.
04:26This makes applications to require large amounts of local storage more complex to develop.
Collapse this transcript
Understanding the architecture
00:00In order to develop HTML5 local storage applications, you'll need to understand
00:04the common architecture that each of these solutions share.
00:08All of the HTML5 local storage solutions share a roughly similar architecture.
00:13The various components of your web application reside on one or more web servers.
00:18These servers can be running any operating system and any web server
00:22software that you like.
00:24The one thing that they all have in common is that they serve up web pages and
00:28web objects using the HTTP protocol.
00:31The application is made of components in HTML, CSS, and JavaScript.
00:36All of these are delivered over the standard HTTP web protocol.
00:41The database interface is coded in JavaScript.
00:44For reasons that will become clear in a moment, the local storage database code
00:48needs to run in the browser and JavaScript makes that possible.
00:52Strictly speaking, any language that runs in the browser could work, but in
00:55practice, there are no real alternatives to JavaScript right now.
00:59Also, the specification notes that the term JavaScript is used in favor of the
01:03more correct term ECMA script because JavaScript is a more widely-known term.
01:09So for all intents and purposes, the database interface must be coded in JavaScript.
01:14All of these components, the HTML, the CSS, and the JavaScript, are requested
01:19by and delivered to the web client, typically a web browser running on a
01:24computer or a mobile device.
01:27The web application interfaces with the client device by virtue of a technology
01:32called the Document Object Model or simply the DOM.
01:36The DOM allows the JavaScript component to access various features on the
01:40client, allowing interactive applications to be developed.
01:44The various interfaces for local storage are actually defined in terms of the DOM.
01:49The Document Object Model is the interface point that allows access to local
01:53storage on the client's machine.
01:55This is actually why the database interface is coded in JavaScript.
01:59JavaScript runs in the browser and has access to the Document Object Model
02:03in the client machine.
02:04That interface is what makes it possible for your application to use local
02:08storage on the user's machine.
02:10So even if your application uses another language to run on the server like PHP
02:15or ASP, you'll still need to code the local storage parts in JavaScript.
02:20All of the various local storage schemes share this common architecture.
02:24So having a basic understanding of this architecture will help you to know where
02:27your code fits in the overall picture.
Collapse this transcript
Running applications offline
00:00Using HTML5's Offline Web Application specification, you can make your
00:04application available for use offline.
00:07Combined with one of the local storage options, this capability can make it
00:10possible to continue using a web application while the client computer is not
00:15connected to the network.
00:16The HTML5 Offline Web Application specification uses a cache manifest file.
00:22This file lists the files required for offline operation and it tells the
00:26browser to save a local copy of the listed files.
00:30This makes the files available for offline use.
00:34The cache manifest file may have any of three sections.
00:38The CACHE section lists the files it must be cached.
00:42This is the default selection, if no section has been specified.
00:46The NETWORK section lists the files that must not be cached.
00:49In other words, these files must be used from the network.
00:53And the FALLBACK section lists the files that will be used in place of resources
00:58that cannot be cached for some reason.
01:01On the JavaScript side, there is an ApplicationCache object that keeps track of
01:05the progress of the cache update and can be used for notification purposes.
01:10So the Offline Application specification can be very useful when combined with
01:15simple local storage JavaScript applications.
01:18This will allow you to provide rich data-enabled applications that can continue
01:22running without network connectivity.
01:24You'll see more details and examples in the Offline Application section of this course.
Collapse this transcript
2. The Web Storage Interface
Providing client-side storage
00:00Many common uses for local storage have traditionally been handled by cookies.
00:04Small bits of information would be stored and named cookies on the client's
00:08computer, mostly for providing context and for satisfying privacy concerns.
00:13Web storage provides limited space data stores that serve as an excellent
00:17alternative to traditional HTTP cookies.
00:20Web storage provides up to 5 or 10 megabytes of local storage and where cookies
00:26are normally sent to the server, web storage data is not.
00:30Web storage provides two different kinds of storage.
00:34Local storage is used for persistent storage of small amounts of data on the
00:38client's computer and session storage is used for storage and will expire at
00:43the end of the session.
00:44Both web storage options use a common object interface.
00:48This makes it easy to deploy different combinations of these local storage schemes.
00:53The rest of this chapter will provide details on how to use these local storage options.
Collapse this transcript
Understanding the Storage() interface
00:00Both of the HTML5 web storage options use the same interface, so programming
00:04for one is just like programming for the other.
00:07In this movie I'm using a working copy of 02-start.html from the Chapter 2
00:13folder of the exercise files.
00:16You'll notice that I'm importing my bwH5LS JavaScript file. So I'm going to scroll
00:23down here to the JavaScript section where we'll be writing JavaScript locally in the HTML file.
00:30And you'll notice I have a little bit of a framework here to get started.
00:33This same framework is what I'm using throughout this course.
00:37Now both the localStorage and sessionStorage objects inherit their interfaces
00:42from a parent class called simply Storage.
00:45And both local storage and session storage are properties of window and they
00:49inherit their interface from that Storage class.
00:52Here we'll be using the localStorage object and when we get to the sessionStorage
00:56object later in this chapter, you'll see how easy it is to switch
00:59between the two, because they have this same interface.
01:03We'll start by detecting support for the localStorage object and I'll do this
01:07by writing a little function called getLocalStorage.
01:19And we're just going to use a try/ catch structure so that we can find out if
01:24the window object has this property without causing the browser to throw an error message.
01:45This double exclamation point in JavaScript is often used to simply cast
01:50something that's not otherwise a Boolean value into a Boolean value.
01:55It's basically not, not, and it's just a little trick that makes the cast a
01:59little bit easier to type and easier to read.
02:02Once you've seen that and you know what it is, it becomes really obvious.
02:05It's not actually one operator; it's really two Boolean not operators.
02:14So what this line does is it checks to see if that localStorage object exists,
02:18and if it does, it simply returns that object from the function, and then we can
02:23assign it to a local variable.
02:26And if this throws an error, we'll simply return undefined.
02:32That's the entire function.
02:33So, that's the easy way to detect if you have the localStorage
02:37property available or not.
02:40And now I'll just come up here and we'll call this variable db and we will
02:45assign it that localStorage object like that.
02:52And I'll display my own error message if it's not supported.
02:58I'm using the display error function from my bwH5LS.js library.
03:11And I'll just press Ctrl+S here and now and then to make sure that my work is saved.
03:17And now that we've detected the localstorage, let's go ahead and use it.
03:20You'll notice that I've assigned it to this variable called db.
03:24So we're going to use the db variable as if it were a localStorage object.
03:29And now down here under display results, right before this line that says
03:34element.innerHTML, that's what displays our results there in our elements with a results ID.
03:42And you'll see that's down here div id =results, and the results show there.
03:49So right before that we're going to go ahead and put in our code that
03:52will display stuff.
03:54The first thing we're going to do is assign some values to our database, so I am
03:59going to use db.setItem.
04:00SetItem is a method of both localStorage and sessionStorage.
04:06And I just give it a name for the item and a value.
04:12And I am going to set a few of these here, so I'm just going to copy this line
04:18and paste in a couple of times, and I'll change this one to destination and
04:26this one to transportation.
04:31And destination will be Ventura. That's where I am recording right now, in
04:37Ventura, California, and I got here on an airplane.
04:41So now I've set a few items in our local storage database and now we want to read them.
04:46So in order to read them, again, I'm using an object from my bwH5LS.js library
04:52and so I'm going to say var t = new bwTable.
04:58And that's just a simple class for creating tables out of tabular information.
05:03It makes it really convenient.
05:05You'll notice here that I use t.getTableHTML to show those results.
05:14And I simply give an array and it will put each element from that array in
05:19a row in the table.
05:20We'll call the first row traveler and I want to use getItem from our db object,
05:29which is our localStorage object.
05:33And get the traveler object just like that and I need to close my array and
05:39close my method call.
05:41Now I'm just going to make a couple of copies of that.
05:44I'm a big fan of cut and paste for coding.
05:48And make this one destination and this one here destination and this one here
05:57will be transportation. And copy and paste likewise.
06:04So now we've done here very simply, this is just for demonstration purposes so
06:09we can play with it a little bit. We've setItem, the traveler item,
06:12to the value Bill, we've setItem destination for Ventura, setItem
06:17transportation to Airplane.
06:18So those items are now set in the database and now all we have to do is get them back.
06:23So we're going to read them from the database and put them in this table with
06:26getItem, getItem, getItem.
06:29So let's go ahead and see how this works.
06:31I'm going to switch to my Explorer window and here is my file. I'm going to open
06:36it with Google Chrome and there it is.
06:41So you see here we have displaying in this table the information that we
06:45entered into the database.
06:47Now there are a couple of other interesting things that we can do with this.
06:50Just to give you a little bit of a tour around the storage interface, you can delete an item.
06:56So if I was to come in here and say db.removeItem and let's just
07:02remove destination.
07:05And I'll save that and come back over to Chrome and reload, you'll notice
07:12the destination now has the special NULL value which shows up in red from my library.
07:17Likewise, I can delete all of the items just by saying db.clear, and reload and
07:26you see that all of those items are now NULL.
07:29Now I'm just going to come back here and take out the db.clear line and and save this
07:35and reload again, and you see we have all the data back.
07:41So the Storage object provides a common interface for both of the HTML5
07:45Web Storage options.
07:47In this movie I've demonstrated its use on a simple persistent data store,
07:51using local storage.
07:52There are more samples in the rest of the chapter.
Collapse this transcript
Persistent storage with localStorage
00:00Local storage can be compared to persistent cookies where the data is stored and
00:03kept between sessions and it's bound to a domain. Unlike persistent cookies
00:08though, this data does not expire.
00:11DOM storage in general is typically limited to 5 or 10 megabytes per domain,
00:15depending on the browser.
00:17It is not intended to be used as a local database.
00:21In this movie I'm using a working copy of 03_start.html from the Chapter 2
00:26folder of the exercise files and it's just a simple HTML file. It's the
00:31results of our last movie.
00:33What it does is just a simple demonstration of the localStorage object.
00:37Right down here in the JavaScript it sets some items in the database and it
00:41retrieves those items in the database with getItem.
00:43This db object is actually the local storage object.
00:49That uses this getLocalStorage function that we wrote in the last movie, which
00:53checks to make sure that we have the local storage capability by checking for
00:57the localStorage property in the window object, and if it's found, it gets
01:02assigned to this variable db right there, and that's what's used for the local
01:06storage functions throughout, this JavaScript.
01:09Here we have it running in Google Chrome and you'll see it just displays the
01:13data in this nice little table.
01:16So now we are going to go ahead and we're going make this a little bit more useful.
01:19You will notice down here we have this form and here in the browser this is the form up here.
01:24So I am going to show you how to do is how to get the data from the form and
01:28go ahead and store it in the database. That will make this a little bit
01:31more useful for you.
01:33So notice that the last element in the form here is this button and so
01:38that's an HTML button there, and it has this onClick calling the dbGo
01:44function in our JavaScript up above. And so here's the dbGo function which
01:49currently doesn't do much.
01:52So let's go ahead and make it do something.
01:54First of all we're going to take these setItems here.
01:57I'm going to go ahead and cut them with Ctrl+X on my PC keyboard, and I'm going
02:03to paste that down here into the dbGo, and instead of these literal values, I'm
02:08going to go ahead and get the data from the form.
02:11So the first thing we're going to do is we're going to get the form object.
02:14So I'm going to say var f =, and again I have a little function in my library called element.
02:22It's just a shortcut for getting an element by ID and the form is called
02:27travelForm and you'll notice that we come down here to the HTML that the form id is travelForm.
02:36So that allows us to get the elements of the form. And then instead of the
02:40traveler name here, I'm going to say f.elements, 'traveler' (in brackets), .value.
02:51And I'm just going to go ahead and copy that and paste it in each of these places here.
03:01And just change traveler to destination and transportation.
03:10And each of those names there that are being used as indexes in the elements
03:14array, each of those names have to match the names being used here in these form elements.
03:21name = "traveler", name = "destination", name = "transportation".
03:26You'll also notice that at the beginning of dbGo we have this line here that
03:29says if(errorMessage) return. That's just checking to make sure that we actually
03:34have the db element.
03:36You'll remember up here, when we called getLocalStorage, if we don't get back an
03:41object, we display error, and over there in the dwh5ls library displaying an error
03:49sets a variable called errorMessage, and that errorMessage gets displayed here
03:55in the display results.
03:57But it can also be just tested. It's just a little convenient shortcut.
04:00I can also test it here to make sure that I don't call this function when the
04:04button gets pressed, if I don't have an actual db object.
04:08So let's go ahead and run this in the browser.
04:10I'm going to save and I'm going to go into the browser and I'm just going to
04:15press Reload and you'll notice that we still have this data here because it's
04:18stored in the database. So it's persistent.
04:21If I come in here and put in something else, let's say John, and John is going
04:27to London, and he's taking a boat.
04:30When I press Go, the dbGo function gets called, this data gets copied into the
04:36database, and it gets stored in the database using setItem, and then down in the
04:41display function it gets red, using getItem, and there it is.
04:46Now whenever I change this data, Bob is going to Paris and he's taking a
04:52rocket, and I press Go and that data gets changed down there as well.
04:57So we're successfully storing data in the database in the dbGo function and
05:02reading the data from the database in the display results function.
05:06Let's just do one more useful thing here.
05:08If you want to clear the data, we're in need to add another Button and so I'm
05:12just going to break this button out on a line by itself here, and then I'm going
05:20to copy it and I'm going to change this. This will be dbClear over here in the
05:30onClick and I'm going to change the button to say Clear. Press Ctrl+S to save.
05:35Now I'm going to come up and write a dbClear function really quick.
05:46I'm going to copy this if(errorMessage) return.
05:49because that will serve the same purpose here, and as long as we have the db
05:55object I can just say db.clear.
05:57If you remember, that is all that it takes to clear the database entirely.
06:03And I'm going to display the results again after clearing.
06:07So now when I come back to the browser and press Reload, you'll notice we now
06:12have this Clear button.
06:13Actually, I would like the Clear button to be before the Go button so the Go
06:17button stands out a little bit better.
06:18So let's just go down here and change that.
06:24That should be much better and I'll reload.
06:27Now we have the Clear button and the Go button and we still have the data down
06:31here because it's persistent to database, but if I press the Clear button,
06:35you'll notice I know have NULLs in my database, NULL, NULL, NULL, and if I put
06:39in some more data, let's see where do I want to go this time.
06:45And how do I want to get there?
06:47Oh spaceship, I like spaceships.
06:50And press Go. Now I have got that data down there in my database and if I press
06:54Clear again, the data is gone.
06:56So now we have made our web page a little bit more functional here.
07:00These are the basic skills you're going to need to be able to use local storage
07:03in your application.
07:04You are going to need to be able to get data from your form elements and
07:08store that data in your database and then retrieve it from your database and
07:11do something with it.
07:12Local storage is designed to be a more robust alternative to persistent cookies
07:17and it works well for this purpose.
07:20Session storage is demonstrated in another movie in this chapter.
Collapse this transcript
Keeping context with sessionStorage
00:00Session storage can be compared to session cookies.
00:03They are stored locally, but they're kept just for lifetime of a particular window.
00:07Unlike session cookies, session storage is bound to a particular instance of
00:12a particular window.
00:14This allows for separate sessions to run simultaneously in separate windows,
00:18something that is very difficult to do with traditional cookies.
00:22In this movie I'm using a working copy of 04-start.html from the Chapter 2
00:27folder of the Exercise Files.
00:29This is the results from the previous movie.
00:31Now as I've mentioned before, the actual interface for session storage is exactly
00:37the same as for local storage.
00:39It just uses a different object.
00:41So I want to just change my getLocalStorage function here to
00:45say getSessionStorage.
00:46And I am going to change each of these properties here to say session instead of local.
00:57Then up here I'm going to call getSessionStorage, instead of getLocalStorage,
01:03and I'll just change my little error message here and that's all that there is to it.
01:08Everything else stays exactly the same.
01:12So instead of assigning a localStorage object to my db variable, I'm now
01:17assigning a sessionStorage object to my db variable.
01:21So all the data that gets stored in red, instead of getting stored in a persistent
01:26database store, it's going to be stored dynamically in a session store.
01:32It will work as session storage instead of local storage.
01:35Let's take a look at what this does.
01:37I am going to press Ctrl+S to save here.
01:39Let's just change the title here, also just to be nice about it.
01:43sessionStorage example there, and down here, sessionStorage example.
01:52And then when I come back up here to the browser and press Reload, it says
01:55sessionStorage example in the title bar and it says sessionStorage
01:59example here as well.
02:02You'll notice that there is no data, but if I add some data to it and press Go,
02:10now that data is there.
02:12And I can press Clear and it gets cleared. Everything works exactly the same.
02:17Now here is the cool part. If I open a new tab and I'm just going to come back
02:22here and I am going to copy and paste,
02:26now I have another instance of this exact same program, but you'll notice
02:31there is no data in it.
02:32And if I put some different data in here, that data stays there. And if I go back
02:43to the first window and press Reload, you'll notice that it's got the previous
02:46data and I press Reload here, and t's got this data.
02:49So let's do one more here. Jane is going to Paris on her Wishes.
03:00If I press Reload, I've got that data in that one. I press Reload, I've got this
03:05data in this one, and I press Reload, and I have this data in this one.
03:10That is something that is very difficult to do with traditional cookies and
03:14this is really the power of session storage over session cookies.
03:19Session storage is able to keep context in multiple windows and this is
03:25something that's extremely challenging to do with traditional cookies.
03:29So the programming interface is virtually exactly the same. Our code didn't
03:34change at all. All we did was recopy the sessionStorage object to our db
03:39variable, instead of a LocalStorage object.
03:41That's all we changed. Everything else remain the same, and now we have
03:46sessionStorage in our browser.
03:48This is a tremendously useful tool, especially for keeping context in multiple
03:53windows, which is something that can be very challenging to do with
03:56traditional cookies.
Collapse this transcript
3. Web SQL Storage
The state of Web SQL Storage
00:00Web SQL Storage is a specification for using a full power SQL storage engine on
00:06the web client's machine. It's a JavaScript DOM interface that uses local SQL
00:12storage for a database and it's inspired by Google Gears.
00:16Web SQL Storage uses SQLite for storage.
00:20SQLite is compact, fast, robust and portable.
00:24Currently SQLite is the only SQL database engine suitable for this use, so all
00:30the Web SQL implementations use SQLite.
00:33Some folks over at the World Wide Web Consortium, the organization responsible
00:38for standardizing these things, considered a bad idea to standardize on one SQL dialect.
00:44So they've stopped working on the Web SQL specification and have stated that
00:48they don't intend to pursue it further.
00:51Personally, I like things that work and Web SQL works.
00:55Unfortunately, it's not available on some of the more popular browsers.
00:59Currently Web SQL is supported by Apple Safari, Google Chrome, Opera, and their
01:04mobile counterparts on the Android and iOS platforms.
01:08It is not supported by Internet Explorer or Firefox, and Mozilla has publicly
01:13stated that they will not support Web SQL in the future.
01:17So the unfortunate state of affairs is that there's a powerful local storage
01:21database option available, but it cannot be used for applications that require
01:25support from the two biggest browsers.
01:27Keep in mind, however, that with full support on both iOS and Android devices,
01:33you can use this solution for many mobile applications.
01:36We'll discuss the alternative, the IndexedDB specification in another chapter.
Collapse this transcript
Understanding the Web SQL API
00:00The interface for using a Web SQL database is fairly straightforward, if not
00:05simple, because database operations may take some time to execute the interface
00:09must be asynchronous.
00:11So the liberal use of callbacks in the interface makes this possible and should
00:15support performance requirements in most cases.
00:18So this is a completed application that uses the Web SQL database.
00:23It looks like this in the browser, this is the Google Chrome browser, which
00:27supports Web SQL and you'll notice that we have these three fields for Traveler,
00:33Destination, and Transportation, and right now there's no rows in the database.
00:37So I'll just add a few rows, I will put in my name, and let's say that I'm going
00:43to California and I'm traveling by plane, and I'll add this to the database and
00:50there you see that it comes up there in our table.
00:53This is entirely being done in JavaScript. It's entirely being done on the
00:57static page without any server involved. You notice it is just a file URL.
01:01There's no posting of data going back and forth. This is all just happing
01:05dynamically in the browser.
01:06And so I'll add another couple of records. Let's say, Jimi is going to London and
01:11he is traveling as he always does by guitar, and we'll say that George is going
01:18to Paris and he's going by rocket. And I'll say Add and you'll notice that
01:24George came up there in the middle, because this is sorted by traveler name.
01:28Now there's three rows in the table and if I want to edit one, like for
01:33instance let's say, well, George isn't going by rocket, he is going by
01:36Slingshot, and you notice that the Add button changed to say Update when I
01:42pressed Edit there. And if I press the Update button, you'll notice it's changes
01:47to slingshot, the button becomes Add again, and these fields get cleared and the
01:52cursor goes back to where we want it.
01:54We have a fully functional application here that would make it fairly easy for
01:58somebody to add a bunch of data if they wanted to, and you notice that we can
02:02edit data. We can also delete data and this is an interesting little thing here.
02:08If I press the Delete button at this point, you'll notice I get a little
02:11confirmation, it says Delete George (ID: 3). I can say Cancel and it won't do anything.
02:16You'll notice that it's got the record up here in the Edit field, so if I say OK,
02:21it goes ahead and it clears that and it resets our whole screen so that we're
02:24back in the Add mode, and it removes it there from the table.
02:27So this is a fairly complete application. It does all of the major functions of
02:33a database, create, read, update, delete, sometimes called CRUD. Those are the
02:37four major functions of a database application.
02:41We also have this nice little Empty button, which will empty the entire
02:44database, I press OK, and it puts us back in a clear state, which makes it nice
02:49for development purposes. If you wanted to just empty the database really
02:53quickly, you can do that.
02:54And so the application is written in JavaScript here, here is our HTML file, so
03:00let's take a quick look through the code here.
03:03It all starts here where we declare the JavaScript. You'll notice that it uses
03:06the same bwH5LS library that all of the applications in this course use.
03:11There is a createSQL variable that has the SQL for creating the database and
03:18the first thing that it does here is it calls prepareDatabase to grab a database
03:22object that can be used throughout the code, and here's the prepareDatabase
03:27function here, which calls us.
03:29getOpenDatabase, that gets the open database object from the window object, and
03:35if that does not exist, it returns undefined, so then it can test that and say
03:40Web SQL not supported.
03:42For example, of what that looks like, let's take a look at this application in
03:45Firefox and you'll notice that we get this message, Web SQL not supported,
03:50because Firefox does not support the Web SQL database method.
03:54And if it's supported, it goes ahead and creates the database using the
03:58createSQL string that we saw up above.
04:02It's got a function for counting how many rows and you'll notice the SQL being used here.
04:08All of the database operations are using SQL because it's using a real fully
04:12functional SQL database.
04:14When we display the results we have a simple SQL select statement and we add
04:22data using insert, we update data using update, and we delete using delete.
04:33So this has been just a brief overview of the Web SQL interface, and in the rest
04:37of the chapter we'll develop this application using Web SQL.
Collapse this transcript
Creating a database
00:00Creating a new database with Web SQL is simple and this simplicity is directly
00:04due to the fact that all the existing implementations use SQLite as the database engine.
00:09In SQLite, when you open a new database, if it doesn't already exist it gets created.
00:15Let's go ahead and write some code that creates a database.
00:18You will notice that I am working here with a file called 03-working.html.
00:23This is a working copy of 03- start.html in your exercise files.
00:29It's a very simple stripped- down version of our application.
00:33That's the entire JavaScript right there and it has the same HTML at the bottom
00:38of our finished application.
00:41I also have here in my editor, 03-copy.txt.
00:46This is simply a text file with some of the stuff that I am going to copy and
00:49paste, so we don't have to type all of this. But that's okay. I'll explain it as we go along.
00:54So, the first thing we are going to do is we are going to get a copy of the SQL
00:58that's used to actually create the database.
01:00So, I am just going to copy and paste this here and drop it into my JavaScript
01:08and indent it so that it's all very nice.
01:11And this creates a variable called createSQL and it's simply one long string
01:15that has the SQL in it for creating a database.
01:19You will notice that to get it to wrap around lines, I am simply concatenating
01:22several separate strings. And that's okay.
01:25The JavaScript does this concatenation operation very, very quickly.
01:29So, we have the SQL CREATE TABLE IF NOT EXISTS and the name of the table here
01:35and then we have the four columns for the table,
01:38id, traveler, destination, and transportation.
01:42id is of type integer primary key and in SQLite,
01:46that's an automatically incrementing value that can be used conveniently as an id.
01:52Each of the rest of these are of text type and if you want to understand a
01:56little bit more about SQLite's types, you can take my SQLite Essential Training
02:01course here on lynda.com and you can learn about the way that it does typing.
02:05It's a little bit different than some other SQL engines.
02:09Now, I want to come back over here and copy this getOpenDatabase function.
02:13So, I am going to copy that and come over here and paste and I'm just going to
02:21indent that with the rest of it here.
02:24And this simply checks to see if this particular browser supports Web SQL.
02:29It uses this double exclamation point.
02:31That's actually two separate Boolean operators to negate it and then un-negate
02:36it just to check and see if this method exists in the window object.
02:41It's a little shortcut.
02:42It casts it effectively into a Boolean.
02:45You will see, this is used a lot for things like this in JavaScript.
02:48And if it exists, it goes ahead and returns it.
02:51Otherwise it returns undefined.
02:52So it's a very simple check to see if this browser supports the Web SQL protocol.
02:58And you will notice that the method name it's looking for is
03:00called openDatabase.
03:02And now we are going to go ahead and get the prepareDatabase function and this
03:09is the part that actually does the work of creating the database.
03:13Copy that and come over here and paste it and then indent it along with the other code.
03:22And what this does, it's really very simple.
03:24It calls the getOpen database function to get that object if it exists from the
03:30window. If it doesn't exist, it displays an error message, Web SQL Not Supported,
03:36otherwise it goes ahead and it opens the database.
03:39It names the database, it gives it a version number, it gives it a readable
03:44name, and a size for the database.
03:47And this size is basically a maximum size.
03:50It doesn't actually create a database of that size, but it tells the browser
03:54this is the maximum amount of space that I am going to need and the browser can
03:57then ask the user's permission or do whatever it's going to do to make sure that
04:02it's okay to use that amount of space.
04:05And you know, it's 10 * 1024 * 1024, so that's 10 megabytes.
04:11Once the database is opened, it starts up a transaction and all of the
04:16database operations in Web SQL are inside of transactions and here's that callback function.
04:22In this case, as in most cases, we will be using anonymous functions, which is a
04:28feature of JavaScript and really most object-oriented languages.
04:33And in this case, this function will execute some SQL.
04:37So the t parameter is the transaction object and that has a executeSql method
04:45and here's the SQL itself, which is our variable, which is up here with the
04:50createSQL statement in it.
04:53This is an empty array because we are not using any parameters with this SQL.
04:57But that's where we would put variables if we were using parameters and we will see that later.
05:02This is a function that is called on success.
05:05This is a function that is called in the case of an error.
05:08And here in the case of an error, we just have a little alert that will tell us
05:12that there was a problem.
05:13In the case of success, just temporarily here, we are going to go ahead and put in an alert.
05:31So, this alert will say Create table to tell us that we've created a table in rows affected.
05:37With SQL statements that don't actually return a value, instead of returning a
05:42value from the database, they will return something called rows affected, which
05:45tells you how many rows in the database were affected by what you did.
05:49In this case, it will affect one row in a special table that keeps track of the
05:53tables in the database.
05:55So when we've created our table successfully, we should get one row affected.
05:59And you will notice here this r object.
06:02This is one of the parameters to the anonymous success function here and that r
06:07is where you will always get you results, from executeSql.
06:11So we have this anonymous function that's being used as a callback from
06:14executeSql and we are just having something happened in it to tell us that we
06:18have successfully created the table.
06:21Now, finally, we just need to make sure that we call all of this.
06:24And up here at the top, we are going to actually create a variable, db, and this
06:30would be where we keep our database object for the duration of this code and
06:35it's going to call this prepareDatabase function.
06:41And now when I save this and we'll come back over to the browser and run it, so
06:46when I hit Reload here, you will notice, it says, Create table, rows affected:1
06:51and that's because it actually created the table.
06:54If I hit Reload again, you'll notice it will say rows affected:0, because the
06:59table already exists.
07:01Remember in our code, it says CREATE TABLE IF NOT EXISTS.
07:06And so if the table does exist, then it doesn't have to create the table
07:10and we'll get that 0.
07:12Now, I just want to show you one more thing real quickly here.
07:15I want to show you where Google actually stores the data.
07:18This can be useful.
07:19Remember, the database is stored in an SQLite database.
07:23An SQLite database basically exists in one file.
07:26On a PC, you will find this file in your user home directory under
07:31AppData/Local/Google/Chrome/ User Data/Default/databases.
07:37On the Mac, you'll find it off your home directory under Library/Application
07:41Support/Google/Chrome/Default/databases.
07:46And in each case, you'll see a folder and the folder will look a little bit like your URL.
07:52And so in this case, it says file__0 because our URL is file and then it's got the
08:00actual path to the file.
08:03But the Web SQL specification says that the databases are associated with a
08:08domain and in the case of a file URL, there is no domain and so it's just file blank blank.
08:15If this URL were an actual http something.com, then the folder would say
08:21http_something._com or something like that.
08:26And so that's how you can identify which folder is.
08:29You may have several folders in here, if you've been surfing around the web
08:32and you may not have realized or you did realize and you have got some Web SQL databases already.
08:37In this case, we don't and when I open this folder, you'll see a file with the number 1.
08:42And yours may be a different number. I know on my Mac because I have done some
08:45surfing around with Chrome already, it said 5.
08:49It could be any number at all.
08:50But that file is the actual SQLite database.
08:54You can open it up with the SQLite command line tool or if you've taken my
08:58SQLite course and you have got a copy of my CyD for SQLite, you can open it up
09:03with that and it works just like any other SQLite database.
09:08So, if I come back here to the databases folder, now I will have to actually
09:12exit Chrome in order to do this.
09:14So I am going to come over here and I am going to exit from Chrome.
09:16I can delete this folder and then when I open Chrome again, Create table, rows affected:1.
09:26It has created that table again and there it is. There is our file__0 folder and
09:32there is our 1 database again.
09:34So I just want to come back here again to my code and go ahead and delete this
09:38alert because we're not going to need this anymore.
09:42So I'm just going to delete everything between these braces here and I'm going
09:46to save and we have now successfully created a database.
09:51Now, because Web SQL is implemented by SQLite, creating a new database is simply
09:56a matter of opening the database file and conditionally creating your table.
10:00In the rest of this chapter, we will be writing the application that
10:04actually uses this database.
Collapse this transcript
Inserting and reading rows of data
00:00Now that we have a table in our database, it's time to go ahead and use it.
00:04In this movie, we'll be writing the code to insert and read rows of data in
00:08our database table.
00:10So here I have opened a working copy of the 04-start.html file from Chapter 3
00:16of the exercise files, and this is the results of the last movie, movie number
00:22three in this chapter.
00:24And this is the code that opens the database and creates the table in the
00:28database if necessary.
00:30So now we're going to go ahead and add some code to insert data into the
00:35database and to read that data.
00:37We're going to start with this function here. You notice I have this
00:4004-copy.txt open and that just makes a little bit easier for us, so we don't
00:45have to type all this code.
00:47So I'm just going to copy and paste this function, pressing Ctrl+C on this PC to
00:52copy it, and I'm going to paste it in down here just above the dispResults
00:57function, and I'll go ahead and indent it.
01:03And so this function, countRows, it simply counts the rows in the table and it
01:08updates this element called rowCount.
01:11I have this shortcut function here from my library that gets an element based on its ID.
01:18Just a simple little shortcut.
01:20And this rowCount element all the way down here is this span.
01:26And so it's just going to take that number and drop it in there.
01:29And if we look in the browser, you'll notice it says "There are _ rows in the table"
01:33 and that's this underscore right there, and that will get replaced with this number.
01:39And so it starts up a transaction.
01:42You'll notice it checks to see if we have the db object, and if not, it does nothing.
01:46We have the db object.
01:48You'll notice instead of the Transaction method, it's the
01:50readTransaction method.
01:51The readTransaction method is a little bit safe and that it doesn't allow you
01:56to do anything that would write to the database.
01:58So if you're doing something that's just reading from the database, it's
02:00recommended that you use readTransaction instead of Transaction.
02:04And inside of our anonymous function, we have executeSql and SELECT COUNT(*)
02:10AS c FROM our table.
02:13Again, there's no parameters.
02:15And this is our success function here, and inside our success function we get
02:20the results object, and from that rows and item(0), because COUNT always
02:26returns just one row of data with one column in it, and .c which is the name
02:32we gave it in the AS clause.
02:35And so I've just named a variable c for the count and I check to see if I have
02:40a count, then I'll return that.
02:42And if I don't have a count, I'm just going to use the number 0 and that
02:46makes it look nice.
02:47And so this is just a little JavaScript conditional expression.
02:51Then the error function.
02:53Again, we have an anonymous function for error and t is the transaction itself,
02:59and the e is the error object and there is a message available from that.
03:04And so if there were an error in the SQL, it would give us a message.
03:09And this gets called from our dispResults function and we're going to go
03:13ahead and paste that in.
03:14We have just a placeholder here for now.
03:18Our dispResults function is a little bit larger than it used to be, so I'm just
03:22going to copy that and paste it in and then we'll take a look at it, and I'll
03:28go back and indent it.
03:30And this part here hasn't changed.
03:35It's checking to see if there's been an error, in which case it will just
03:38display the error message and do nothing else.
03:41It then calls countRows, so every time we update the display we're going to be
03:45updating the count in rows, and you'll see that that will come in handy.
03:49And then we check again if we have a database object, and if we do, we're doing
03:54another read-only transaction.
03:57And it's just a SELECT.
03:58And in this case, SELECT * FROM our table ORDER BY LOWER(traveler).
04:05And so that will always ordered by the name of the traveler and by using the
04:09LOWER function it will be case insensitive.
04:12So again, we have no parameters and our function, we create a new table object
04:18and we set the header.
04:20Then we simply step through the rows, and you'll notice that the rows object has
04:23a length and we step through it using this for loop.
04:27And so for each row we add a row to the table.
04:31Here's our table object.
04:32Add a row with the traveler, the destination, the transportation, and a little
04:38string that says edit/delete buttons.
04:39That's just a placeholder because we're going to have some buttons for that later on.
04:44And then we update the results element and again down here in our HTML, here's
04:50the results element.
04:54And we give it the value from our table, getTableHTML, and we set the focus to
05:01the traveler in our form.
05:03Now displaying all that data isn't going to be very useful if we're not adding
05:07some data to the database. So before we do anything else, we're going to go
05:10ahead and put one more function in here.
05:12I'm going to save what we've done so far and come back over here to my copy.txt.
05:16And I'm going to grab both of these functions here, the dbGo and the
05:25resetTravelForm, because we're going to use both of those.
05:28Copy that and come in here and paste it in here and I'll go ahead and indent.
05:40And then we'll take a look at what we've got here.
05:41dbGo, this gets called when we press the button.
05:45If you come down here into our HTML, we have onClick and we call the dbGo function.
05:51And so that gets called directly.
05:53And it's just doing a little bit different of a check here.
05:55This will work fine.
05:56it's checking to see if we have an error message, in which case we know that
05:59we don't have a database object and things aren't going to be working, so we'll just return.
06:04It's grabbing the travelForm element into f and then it's getting all of the
06:09values from the travelForm.
06:13It checks to see if we have a value for traveler or destination or transportation.
06:18So if we haven't filled in any of these fields, then nothing will happen when
06:22you press the button.
06:24Then it starts a transaction. This time it's using transaction without the read.
06:28It's not readTransaction.
06:29this is a transaction that's going to actually make some changes to the database.
06:33And we have our SQL. INSERT INTO Travel these three columns and these three values.
06:39You'll notice these are placeholders and here we have the parameters array and
06:44this is the data that will go in those placeholders.
06:47You want to make sure you do it this way instead of putting the data directly in the string.
06:52This helps to overt SQL injection attacks.
06:56And so you always want to make sure you use parameters for your values as you
07:00add data to a database.
07:02In the case of an error, this function here will get called, which just puts up a little alert.
07:07And in the case of success, this function here gets called, which resets our travel form.
07:12And we have down here the resetTravelForm function and then the dispResults
07:19happens to update the screen with the new data.
07:22So the resetTravelForm function is actually very simple.
07:26It goes through each of the fields and it sets the value to an empty string,
07:32and it makes sure that our Action is back to add and our goButton is back to Add.
07:36And that just matters after we're doing editing, but we're not doing editing right now.
07:40So those will already be those values but it doesn't hurt to go ahead and set them.
07:45But having this pulled out as a separate function rather than having this code
07:48inline here allows it to be reused.
07:51So it saves space and it also prevents errors from happening.
07:55If you change something, you only have to change it in one place.
07:58You don't have to remember all the places to change it.
08:00So this is a convenience to have this called out separately like that.
08:05So let's go ahead and see this in action.
08:07I'm going to go ahead and save and we will come back at here to our browser
08:11and I'm going to press Reload.
08:13And you'll notice that because we have our display function in here now,
08:18the header for the table, and that happens up here in the dispResults,
08:23setHeader Traveler, Destination, Transportation, and a blank.
08:29And so there is our header and I'm going to go ahead and add some data here.
08:33I'm just going to put in x, y, and z and say Add, and that gets added to the database.
08:39Over here I press the Add button and dbGo gets called and INSERT INTO the table,
08:46our data from the form, and the data gets filled into the form here.
08:50And I'll go ahead and I'll add another one, a, b, and c, and those get listed
08:56before the x, y, and z because it's in alphabetical order.
08:59You'll notice also that our count is displaying correctly.
09:02If I go ahead and add another record, d, e, and f and click Add, you'll notice
09:09that the count gets updated to 3 rows in the table.
09:12So all this is working exactly as we expect.
09:15Our application is now coming together.
09:17We're adding data to the database and we're displaying it in a nice table.
09:21In the next movie, we'll see how to edit rows.
Collapse this transcript
Editing rows of data
00:00Now we have a working copy of a web application that stores data locally on the
00:04client machine using Web SQL.
00:07In this movie we'll implement an edit function so that we can change data that
00:11we have already entered.
00:12So we take a look at the application here, this is my working copy of
00:1705-start.html and you'll notice we have these placeholders for
00:23edit/delete buttons.
00:24This is where we left off in the last movie.
00:26So in this movie we are going to go ahead and put in these edit and delete buttons.
00:29We will hook up the edit button and we will hook up the delete button in the next movie.
00:33And so when you press an edit button, it will populate this form up here with
00:37the data from that row and it'll change this Add button to say Update and
00:42it will give an opportunity to update that data and then it will update it on
00:45the display as well.
00:47So here's my working copy of 05-start.html, and again, that's the place where we
00:52left off in the last movie.
00:54I've also got 05-copy.txt. This is the code that I will be copying and pasting
01:00so that we don't have to type it all.
01:02So let's go ahead and get to work.
01:03The first thing that we are going to do is we're going to put in those edit
01:07and delete buttons.
01:08And so we are going to scroll down here to where we have dispResults.
01:12I going to come over here in my little copy file and I am going to grab
01:17this function here.
01:20Copying that and then I'll paste it in place here.
01:24And I am going to go ahead and indent that.
01:30So this is simple function called rowButtons and all it does is returns a
01:33string and this string has the edit and delete buttons.
01:37You'll notice that the edit button has a value Edit.
01:41That's the text that it will display on the button.
01:43And onClick it calls a function called editGo with the value of the id field.
01:50And that value gets passed to the function here along with the value of the traveler.
01:56And so if I come down here into dispResults, you notice that I have this
02:01placeholder here for the Edit/Delete buttons.
02:03I am going to go ahead and instead I am going to call my rowButtons function and
02:11I am going to pass it the value of id, which is row.id, and the value of the
02:16Traveler, row.traveler, and I need to close parenthesis there.
02:22I'll save my work so far.
02:26Now when this button gets pressed, it's going to call this function editGo and
02:30it needs to pass the id value in there.
02:33So we are going to scroll here and just pass our dbGo function.
02:38We will go ahead and paste it in right there and there is the editGo function.
02:44We'll take a look at that after we have pasted it in.
02:46We will put it right in there and I'll go ahead and indent that.
02:53And so this is very simple. It uses readTransaction and it executes this
02:58executesql here, which is a simple select where it is going to select one
03:01row from the table, where its id is equal to the value passed into the function there.
03:07And then in the anonymous function that gets called when the data is returned,
03:12it takes that one row, row number 0, and it populates the form, so this is our
03:17travelForm, you remember.
03:19Down here in our HTML there is our travelForm. And so it goes head and populates
03:27that form with the values from the row that we get from the database table.
03:32So we have traveler, destination, transportation and that will go in those form fields.
03:37The button will get changed to Update.
03:40The inputAction will get changed to a value of Update and we will look at that
03:44in a moment, and the key gets the value of the row.id, and then we set the focus
03:50and select the value in the Traveler field.
03:54Now inputAction you'll notice down here in the form,
03:57we have a couple of hidden fields here, action and key, and those are IDed with
04:03inputAction and inputKey.
04:06And so now what we are going to do is we are going to update this dbGo
04:10function so that it will either insert data if the action is the default
04:16value, which is Add-- see there is the action add-- or if the action is update, it
04:24will update the data instead.
04:26And so that way when this button says Update and you press the button it will
04:31update the database instead of inserting into the database.
04:35And so what we are going to do is we are going to replace this piece of code
04:37right here with this code from our copy file.
04:43I'll copy that and I will paste it in here and I'll go ahead and indent it and
04:54I will take a look.
04:55So now we have this switch statement and switch is like a multiway if-else.
05:01You can think of it that way.
05:02It's a little bit more flexible than that, but it takes a value.
05:05If the variable is this value, it will do this code, and if the variable is this
05:09value, it will do this code, and you can put several of them in there and
05:13that's what switch is for.
05:15And so if it's Add, and this is the action. Remember here this is from the
05:20inputAction element in the form.
05:22That's the hidden field.
05:24If it says Add, then you will go ahead and this is exactly the same code that we
05:28just replaced, and it will do the insert into the table.
05:32If it's Update, then it will update the data instead, in the row in the table.
05:37And it uses the key. So here is our hidden field, key from the form, and
05:44that has the id in it.
05:46Remember we populated that with the row.id when we populated the form.
05:52And so, this update has placeholders for traveler, destination, transportation
05:57where id equals, and that's where we put the key, and there is the values for
06:02the other data. So that will update the table.
06:06So let's go ahead and see how this works.
06:08I am going to save it here and we'll switch to browser and I'll hit Reload, and
06:13there is our Edit and Delete buttons.
06:15Now we have hooked up the Edit button.
06:16We haven't hooked up the Delete button yet, so I am going to go ahead and press
06:19the Edit button with this middle one, d, e and f. And there is our data populated
06:24into the form and the button got changed to say Update.
06:28Now I am just going to put some other data in there.
06:30I am going to put in my name and my destination and how I travel, and I am
06:37going to press Update.
06:38And you'll notice that that gets updated in the database and it gets displayed.
06:42Our row count stays the same. It simply updated that field in place.
06:47If I were to update this x, y, z, and put in something that sorts before
06:51Bill, and I put in Alpha and destination Omega, and transportation can be
06:59Language, and I hit Update, you'll notice that it resorts the table and it
07:05goes in there before the Bill.
07:07Now that's the middle one.
07:08Now our application can edit the data in the database, so all that's left is the
07:12ability to delete and that will complete the four basic functions of a database
07:17application: create, read, update and delete, sometimes called CRUD.
07:22In the next movie we will implement our delete function.
Collapse this transcript
Deleting rows of data
00:00At this point, we have a database application that creates a database and
00:04a table, it adds data to the table, it displays the data, and it can edit the data.
00:09This represents three of the basic four functions of a database application.
00:13When we add the ability to delete data, the application will be complete.
00:18Here I have a working copy of 06- start.html from the Chapter 3 folder of
00:24the exercise files.
00:26And this is where we left off in our last movie and over here I have
00:3106-copy.txt which gives us some code that we can copy and paste into the working
00:38file so that we don't have to type it all.
00:40It's not a lot this time, but it's a convenience.
00:44And here in the Google Chrome browser, the application so far, this is
00:4806-working, this is what I have opened in the editor.
00:51You'll notice the database hasn't changed from the last movie because that's
00:55actually stored here on the machine that's running the browser.
01:00So when we take a look at these buttons here,
01:02this is the Edit and Delete button, that's these two buttons here in each row,
01:07you'll notice that the Delete button calls a function called deleteGo and it
01:12passes a couple of parameters to it.
01:15It passes the value id and as a literal string with quote marks around it using
01:21these HTML entities for the quote marks, it passes the value of traveler.
01:25And it gets these down here in the dispResults function as it adds the row to
01:33the table traveler, destination, row.transportation, and the string returned by
01:38rowButtons, and it passes right here the id and the traveler from the database.
01:43So down here you'll notice the editGo function and that gets called by the
01:48Edit button and so now we're going to go ahead and we're going to add our deleteGo function.
01:54And so I'll come over here to the copy.txt and we'll just copy that
01:58function, paste it in, and go ahead and indent it where it belongs and there we have deleteGo.
02:08This is a very simple function.
02:11It uses a confirm, which is like an alert box, although it asks you to press
02:17OK or Cancel and it says Delete traveler, question mark, and it gives you
02:22the ID number as well.
02:25And if you respond in the affirmative by pressing the OK button, it goes ahead
02:29and starts up a transaction and it executes this very simple SQL DELETE FROM the
02:35table WHERE id = and it passes the ID number.
02:39Then it resets the travel form with the resetTravelForm function and that's just
02:45right here and it displays the results.
02:48Very, very simple code.
02:49So I'm going to go ahead and save that and we'll switch to the browser and I'll
02:54reload in the browser.
02:55And I'm just kind of go ahead and I am going to delete this row right here. a, b, c.
02:58So I am going to press the Delete and you notice we get this lovely little
03:03JavaScript alert box.
03:04It says Delete a, because that's the traveler name there.
03:07I want to just say Cancel.
03:09We'll go ahead and put something a little bit more descriptive in here than a.
03:12I am going to edit it and you'll notice that my first form field gets highlighted.
03:16I don't even have to touch it with the mouse and I'll just put in there Zaphod.
03:21And his destination is the End of the Universe and he gets there by Time Machine.
03:30And I'll say Update and there is Zaphod at the end there.
03:34And now if I say Delete, I get this confirm and you'll notice when I press
03:38Cancel nothing happens. But if I say OK, it deletes it, it redraws the table,
03:44and we're right back in place where we can add another record.
03:47So I am going to just go ahead and add another record and put in Jimi and his
03:51destination is Rock and Roll and he gets there with his Guitar.
03:57And I'll say Add and there he is there.
03:59And here is another interesting feature.
04:02if I say Edit here and then I press the Delete button, you'll notice that the
04:06form is still in its edit mode.
04:08The data is up there and it says Update and that's the same record that
04:13I'm going to delete.
04:14And you'll notice here in our code, after we do the delete we do
04:19the resetTravelForm.
04:21So after the record is deleted, we'll go right ahead and reset the travel form
04:25and display the results.
04:28So resetTravelForm, it clears out all of the fields in the form, it sets them
04:34all to value equals an empty string, and it sets the inputAction back to add and it
04:41sets the goButton value back to Add.
04:43So this ensures that when I press OK here that I'm not left in a state where
04:48I can hit Update and I can try to do an SQL update on a row that doesn't exist anymore.
04:54So I am going to say OK here and you see that our form goes back to normal.
04:58So even when I say Edit and I've got that data up there and I say Delete for
05:03exactly the same record, I can't get left in a state that doesn't work.
05:09So one more thing we want to do here.
05:11You'll notice we have this little Empty button here and that will empty out the
05:14entire table and that will put our table back in an empty state.
05:18That can be real useful during debugging.
05:20It's not something you necessarily want to give to an end user, but for our
05:24purposes I find it really convenient.
05:26So let's go ahead and implement that.
05:28And if we look down here in the HTML, you notice that we have this button,
05:32value="Empty", onClick clearDB.
05:36And so we're just going to come back up here and right here before the initDisp,
05:40we're going to paste in this clearDB function. It's very simple.
05:45Again, copy that and paste it and we'll go ahead and indent that and we'll take a look.
05:54Again, we have a confirm box, Clear the entire table?, and a simple transaction
05:59that says DELETE FROM.
06:01And because it doesn't have a WHERE clause, you remember our delete for a single
06:07row has a WHERE clause, this will actually delete every row in the table.
06:11It's something that you don't normally want to do, but when you do need to do it,
06:15it can be a very efficient way to delete an entire table.
06:19Virtually, every database engine I know of optimizes this into just rewrite the
06:24table from scratch with nothing in it.
06:26So it's very quick.
06:28So I am going to go ahead and I am going to press Save here and we'll come back
06:32here and reload and we'll press the Empty button.
06:37Clear the entire table?
06:38If I say Cancel nothing happens and if I say OK we get an empty table.
06:44So now we have a completely functional database application that stores its data
06:48on the client's computer using Web SQL.
06:50This represents a very powerful capability.
06:53Unfortunately, because it uses Web SQL for data storage, it will not run in
06:58Internet Explorer or Firefox.
07:00And both of those browser manufacturers have indicated that they're not going to
07:04be implementing Web SQL in the future.
07:06In the next chapter, I'll show you another option called Indexed DB that works in
07:11the latest version of Firefox and that Microsoft is planning to support in its
07:15upcoming versions of Internet Explorer.
Collapse this transcript
4. The Indexed Database API
The state of IndexedDB storage
00:00Indexed DB or the Indexed Database API was originally called Web Simple DB. It was
00:07originally proposed by Oracle and has since been promoted and implemented by
00:10Mozilla for their Firefox browser.
00:13It uses a key-value database model, typically implemented on top of B-tree
00:18database engine, although the Firefox implementation does use SQLite.
00:24IndexedDB supports stored objects, not just strings or scalar values.
00:30Currently Indexed DB is only supported by Firefox 4.0. Google and other browser
00:36manufacturers have planned support for their next versions.
00:40Indexed DB with its key-value hierarchical model does have some limitations when
00:45compared with the traditional relational database.
00:48The enumeration operations can be inefficient.
00:52It cannot search for values directly in its datasets.
00:56There's no easy way to join datasets and coding for Indexed DB can be
01:01convoluted and verbose.
01:03And the Indexed DB API uses JavaScript keywords for some of its object methods,
01:10creating conflicts for browsers like Internet Explorer and WebKit as they try
01:15to develop the interface for their browsers.
01:19The Firefox implementation of Indexed DB is still considered in development, so
01:24expect it to change, and there's a few things that are inconsistent or don't work right.
01:29Also, this implementation cannot use file-based URLs, so this means that for
01:34development purposes you must use a server. You cannot work on your JavaScript
01:39files directly off of your file assistant.
01:41This can make development cumbersome. For our demonstrations I'll be using my
01:45web server. You must use your own web server.
01:47Mac OS X, ships with Apache and Windows ships with Microsoft Internet
01:54Information Server, so you can use one of those servers, or you may download
01:58something like XAMPP.
02:02If you need help installing a web server for your development machine, see
02:06David Gasser's excellent installing Apache, MySQL, and PHP on lynda.com.
Collapse this transcript
Understanding the IndexedDB API
00:00The interface for using an Indexed DB database is very different than that of Web SQL.
00:05Because the database operations are all handled by object methods, rather
00:10than SQL, the interface is more complex,
00:13the use of callbacks is more pervasive, and the object structure can be
00:17confusing, and because of the proliferation of asynchronous callbacks,
00:22you need to be aware that database operations may not always happen in the
00:26sequence that you expect them to.
00:28Indexed DB has both a synchronous and asynchronous mode and as of this
00:34recording date the synchronous mode is not yet working in Firefox and Firefox
00:38is the only browser with Indexed DB support in its released code.
00:42So we'll be using Firefox and will be using asynchronous mode.
00:46Asynchronous mode is probably the best choice for most applications anyway,
00:51which is probably why Firefox decided to implement that first, because it's
00:57going to give you the best performance.
00:59So here's our demo application. iI you went through the chapter on Web SQL
01:04you'll see that it looks pretty much the same. We're creating a little database
01:09of travelers and if I put in a name here and a destination and a
01:15transportation method, and I'll click on Add and we see that that gets put in
01:22the database there.
01:24And if I add another one, Pamela likes to travel by rocketship, we see that gets
01:34added and I'll add yet one more. And you see that one comes up in between,
01:45because the name sorts this way. So these are sorting by the traveler name.
01:50So this is working pretty much exactly like our other application for Web SQL. I can edit these.
01:56I can say instead of going to South America he's going to go to Guatemala, and
02:04you see that gets updated there in Destination. Or if I want to delete one, I
02:08can just delete that and say OK, and that get deleted, or I can empty the
02:13entire table. This is useful for development purposes if you want to start with a fresh database.
02:20Now you'll notice that I'm actually running this on a server. This is because
02:24one of the little quirks of Firefox isn't it won't allow any local storage
02:30based on a file URL.
02:31In other words, if my URL starts with file and that would be the only way to
02:36open a file on my local file system, rather than through a server, it will
02:41refuse to use any of the local storage options.
02:45So because of this I've had to load this up on a server.
02:48Now I'm using my own server. If you are taking this course and you're learning
02:52about web development, you will need a server anyway, so presumably you have
02:57one available. You can either hire a server at one of the hosting companies.
03:01You can get them very inexpensive for a little bit of development use or you
03:06can load up a server on your local machine and there are a number of options for doing that.
03:11There's an excellent course here on lynda.com called Installing Apache, My SQL
03:16and PHP, which would give you the skills you need to do that.
03:20But I'm just assuming that if you're taking this course you are interested
03:23in Web development and you already have access to the server, so I've loaded
03:26this up on my server. And you'll notice that I'm also editing the file
03:30remotely through a plug-in in Notepad++. It's this NppFTP, and it's actually
03:37connected using SSL, not using just their FTP. I don't recommend do anything
03:42like this over FTP.
03:44Use SSH if that at all possible. And here on the PC, you can use Notepad++.
03:50It comes with this plug-in already installed.
03:52Or if you're on Mac, you can use BBEdit or its free alternative, which also has
03:59built in the capability of editing remotely using SFTP or SSH.
04:04So I'm editing this file actually on my server. And you'll notice that this is
04:09pretty much the same as what we have in the Web SQL, if you took that chapter
04:15also, and it's just a simple HTML page and it's got a bunch of JavaScript.
04:21So we'll go through the JavaScript in a lot more detail later in the chapter,
04:25but just by way of overview we have a function here, getIndexedDB, that checks to
04:30see if the Indexed DB interface is available in your browser. And you'll notice
04:35that it tries a number of different object names, and this is because with the
04:40specification still in flux, the browser manufacturers are using prefixes, so in
04:45fact, this is the one that gets used for Firefox.
04:49But this same code, assuming that the interface doesn't change, which it probably will,
04:53but the same code should work once it's finally released and uses the
04:57window.indexedDB object name.
05:01So it opens the database using the openDB function, and that actually gets
05:05called up here at the top, openDB.
05:08openDB in turn calls the getIndexed DB. There is a global ErrorHandler and we'll
05:15get into that a little bit as we look through the code.
05:18This very complicated looking piece of code is how you open the database and
05:23again, unfortunately because the Indexed DB interface is so complicated,
05:29some things that seem like they ought to be really simple are in fact not.
05:33But a lot of other things are really simple.
05:36Another thing we'll notice is there is this retry display. One of the things
05:40that I found while developing this is that on some machines it would work fine.
05:45And on other machines it would get a little bit out of sync, where opening the
05:49database took longer than it took for the JavaScript to get around to trying to
05:54read from the database. And so if the database isn't quite open, I test this
05:58DB variable, then I call this retry display and it'll retry up to five times
06:04using the SetTimeout function from JavaScript.
06:09Adding a record to the database is fairly straightforward. This is the code for
06:12adding. This is the code for updating. There's actually a method in the
06:17specification for updating called Put, and I found that that wasn't working as
06:21I expected it to in Firefox.
06:23So instead I delete and then add,= and that actually ends up being just fine, and
06:29in fact, that's probably what Put does anyway.
06:34And Delete is similarly very simple. It's just basically this one line of code
06:39and likewise there is a method called Clear for clearing all of the data out of a database.
06:46Now I just wanted to show you real briefly a couple of things here.
06:51If we run this in Safari, you notice that we don't get any message at all and
06:58the reason for that is that it's not parsing the JavaScript properly.
07:02One of the problems with Indexed DB is that it actually overloads some otherwise
07:08reserved words in JavaScript.
07:11For example, to advance a cursor, there is a method called Continue, which is a
07:16reserved word in JavaScript and to delete a record from the database, there is
07:22a method called Delete, which is a reserved word in JavaScript.
07:26And the current version of the JavaScript parser in Safari is actually
07:31having problems with that.
07:33It never actually loads up the JavaScript enough to be able to display that
07:38error message, so this is what you get when you try and run this in Safari
07:42and it's not working.
07:43I expect that this will be working in Safari sometime in the next year.
07:48So this has just been a brief overview of the Indexed DB interface. In the rest
07:52of the chapter we will develop this application using Indexed DB.
Collapse this transcript
Create an IndexedDB database
00:00Creating a new database with Indexed DB is a little bit more complicated than with WebSQL.
00:06Partly, this is due to the indirect nature of the interface which sometimes uses
00:10event handlers within event handlers.
00:12This is further complicated by the fact that the only implementation in a
00:16released browser is still experimental.
00:19Here I have a working copy of 03- start from the Chapter 4 folder in the
00:25exercise files, and you'll notice that I'm editing it on the server.
00:29And I also have the 03-copy.txt file from the exercise files open, and this has
00:35the code in it that we're going to copy and paste into our application here.
00:39And that just saves us some typing.
00:41I'll go ahead and I'll make sure that I explain everything as we do this.
00:45So this is a very beginning starting place.
00:48You'll notice that the HTML file is like this and it has very little bit of
00:55JavaScript in it, just a little starting place.
00:57You'll also notice that I'm using this bwH5LS library.
01:01This is my own library that I created for this course and it just gets some
01:05things out of the way that we have in all of the pages
01:08that isn't necessarily directly related to the local storage options that
01:13we're talking about.
01:14So let's go ahead and open an Indexed DB database.
01:17We're going to start by copying in a couple of variables and a little bit of
01:21front matter here. Copy that over, and paste it in and indent it.
01:28And here we declare a db variable.
01:30This will be used for accessing the database throughout the application, and
01:34a dbVersion variable that will be used in a moment in our opening the
01:38database code, and a call to the openDB function that we're going to paste in here in a moment.
01:45Before we do that, we're going to paste in this code here which checks to see if
01:52the browser supports Indexed DB.
01:54And this, like so many things in Indexed DB, is a little bit more complicated.
01:59And this is more complicated due to the fact that the specification isn't really
02:03finished and implementations that are available are still works in progress.
02:08So what this does is it's looking for the indexedDB object to see if it can find it.
02:13The first thing it checks is whether or not the window.indexedDB property exists.
02:19And if it doesn't, then it tries to assign one of these other properties to it,
02:25window.mozIndexed DB, and so this moz prefix that stands for Mozilla, which is
02:32the internal name for the engine behind the Firefox browser.
02:37And they typically use an moz prefix for things that are works in progress.
02:42And then this other one is for the WebKit-based browsers like Chrome and
02:46Safari and Mobile Safari.
02:48The Indexed DB interface is not yet available in the released versions of these
02:53browsers, although there may be some alpha versions floating around that support it.
02:58And so if either of these are available and it checks first for the moz one and
03:03then for the WebKit one because the moz one is more likely to exist today, then
03:08it'll assign that to Indexed DB and then it'll come down here and test for the
03:12existence of that and return that.
03:14And so we do end up with it in the place that we want it to be.
03:19And so this is all inside an exception handler block that'll just return
03:23undefined if it doesn't work.
03:26So this is actually pretty reliable.
03:28So now we're going to go ahead and open the database.
03:32We've got this global event handler that we want to copy in there first and
03:37we'll talk about that in a little bit.
03:43And we'll copy in the actual DBopen function.
03:54Now you'll notice in looking at this code, it looks a little bit complicated
04:03and well, that's because it is.
04:06So the first ting it does is it calls this getIndexedDB, which we just talked
04:10about up there, to see if it can get the IndexedDB object.
04:14And if not, it displays an error returns.
04:16And this is the dispError function from my library which sets a variable which
04:21can easily be tested later on, like down here in dispResult to test for this
04:26variable to see if there's been an error.
04:29So if it does find the object, then it goes ahead and inside of this exception
04:34handling block, it opens the database.
04:36And the reason for the exception handling block, even though there is very
04:40sophisticated error handling available in the interface, it's not used very much.
04:45I imagine it'll be used a little bit more in the future, but for now most errors
04:49tend to throw exceptions.
04:51So first thing we do here is we use our iDB object and we call the open method
04:56and give it the name of our database and a little descriptive text.
05:02This returns a request object, and this is a very common paradigm in the
05:06Indexed DB interface, and we set up onerror and onsuccess event handlers.
05:14So we do this by setting these event handlers to a function and in this case
05:18I'm using an anonymous function.
05:20Anonymous functions are the most common ways to do this, and so the onerror will
05:24display the error display message "Failed to open the Indexed DB database."
05:29The success handler, which actually, all the way down there, is all this other
05:36stuff that creates the database. If it successfully opens a database, we get
05:41this onsuccess event and the event handler then knows that we have a db object.
05:46And this db object, it's copied into our global db variable which is used
05:52throughout the rest of the program.
05:53So we now have successfully retrieved the db object,and it was a little bit of
05:57a roundabout to get there.
05:59And then we set our global error handler on the db object, which is this
06:03dbErrorHandler function that got defined up here.
06:07And so that way, there's a global error handler.
06:10Another way to do that is to have specific error handlers for all of your
06:13database operations throughout your code, and you can certainly do that.
06:17For now, this seemed like the easiest way to do it and the easiest way to get
06:20some of that extra complexity out of the way so that we can learn about the
06:24code here rather than getting buried in the details.
06:27Then we check the version of the database.
06:29Now if the database is already been corrected, the version will be this version here.
06:36And if it hasn't been, then we know that we need to create the database.
06:41And so we check if db.version is not equal to the version that we've defined up
06:46above, and if it's not, then we call setVersion.
06:51Again, that gets a req object and we have an onerror and onsuccess.
06:56onerror is just going to set this alert and onsuccess goes ahead and
07:03creates the object store.
07:05Now the object store is analogous to a table in a relational database.
07:10This is where you store a group of related objects.
07:15And so in this case, we call this db.createObjectStore and we give it the name
07:20of the object store and some optional parameters.
07:23And notice I've got word wrap turned on here so that wraps around of the next line.
07:28The parameters are given in a anonymous object notation and so there's a
07:33keyPath, id, and autoIncrement.
07:36And these are really the only parameters that are legal at this point anyway in
07:41this particular object definition.
07:44So keyPath gives the name of the primary key for this object store and
07:50autoIncrement, it's set to True here and that means that this will
07:53automatically be generated and incremented in each object in the object store.
07:58And then I'm also creating an index here.
08:01The name of the index will be traveler and this is the key path for the index.
08:06And so each of my objects is going to have a property called ciTraveler and ci
08:11stands for case insensitive.
08:13And the purpose of that is so that we can sort our list by Traveler and it'll
08:18be case insensitive.
08:19If it wasn't case insensitive or if we just used the Traveler property, all of
08:23the lowercase ones would be next to all the lowercase ones and then all of the
08:27uppercase ones would be later.
08:28So this allows us to have that be case insensitive.
08:32Now in the event that any of this fails, we'll catch the exception and we'll
08:37just get this error message here that says "Browser supports Indexed DB but
08:41didn't open the database."
08:43So yes, that it is a pretty complicated way to open a database, but that's how
08:48it's done in Indexed DB.
08:51Now there's just a couple of more things we want to add here before we go
08:54ahead and test this.
08:55This retryDisp function.
08:59We'll talk about this in a moment. Let me paste it in here first, and that goes right there.
09:08And then we've also got this main display function. We're going to replace the
09:12one that's already in the code and so I'm going to come down here and I'm going
09:16to select all of this and press Ctrl+V to paste it in and replace that and go
09:23ahead and indent that.
09:25So let's go ahead and press Save here.
09:28Now this is again one of the effects of this asynchronous interface.
09:33When I first built this code on my Mac, it worked just fine.
09:37And then when I came into do this recording and tried it out on a PC, I found
09:42that sometimes I would load up the page, but the database wouldn't show even if
09:47there was already a database and it already had data in it.
09:49And the reason for that is the asynchronous nature of these event handlers.
09:54When the database gets opened, it returns this request object and then you set
10:00the onsuccess event handler and in that onsuccess event handler, the first
10:05thing that happens is that the db object gets set to its valid object value.
10:10But in the meantime, the code is moving along in a different thread.
10:15And what can happen and actually does happen sometimes is it'll get all the
10:19way down to the end of the JavaScript and window.onload fires, initDisp fires,
10:25dispResults gets called and this db variable hasn't been set yet.
10:30This code here is actually happening in another thread.
10:34And it may take longer than it takes for JavaScript to get around to trying to
10:39display the results.
10:40And so what I had to do is if I don't have a db object but I also don't have an
10:46error message, then chances are I'm going to have a db object in just a moment.
10:51So what I do is I call this retryDisp function.
10:54This retryDisp function, it counts to 5 and each time it tries setting a
10:59Timeout and waiting 100 millisecond, and then calling dispResults.
11:05And that'll also happen asynchronously because that's what this setTimeout does.
11:10Over the course of a half a second, chances are we're going to get our database,
11:14if we're ever going to get it.
11:15And so this solved the problem.
11:17This problem just happens because of the asynchronous nature of this
11:20interface, but the asynchronous nature of the interface actually gives us some
11:24performance advantages.
11:25So it's probably a reasonable price to pay.
11:28Now here's what we expect to have happen when we run this in the browser.
11:33If the database does not exist, then we're going to actually create the object
11:38store and when we create the object store, we'll see this alert that says
11:42"Creating the object store."
11:43And even if the database does exist, we get down here and we actually have our
11:48db handle, we're going to get this alert that says have db.
11:52So if we come out here and run this in the browser, and I'm just going to press Reload here.
11:56I've got this loaded up on my server. You notice that I get the alert that says "have db."
12:02That's this one here, have db, but it's not giving me the one to create the
12:07database because the object store already exists.
12:10In order to test that, I need to actually delete the object store and create it anew.
12:16Now in order to do that, I have to actually close the browser because the
12:20browser won't allow me to do while it's got the file open, so I'm going to
12:23close that, and I'm going to come over here to this explorer window here and
12:28here is the full path.
12:30Now on a PC, this path is your user home directory followed by
12:35AppData\Roaming\Mozilla\Firefox\ Profiles\ and then the name of your profile,
12:47which is a random eight-letter and digit name followed by .default, and a
12:53backslash and indexedDB.
12:55So that's quite a bit of a path there.
12:58Now if you're on a Mac, you'll find it off your home directory in
13:01Library/Application Support/Firefox/Profiles/, that random profile name, .default/indexedDB.
13:14Now in this folder, you'll see we have another folder that's named http and some
13:20plus signs and then the domain name.
13:24And inside of that, you'll find this file that ends in .sqlite.
13:27So what we're going to do is we're actually going to delete this whole folder
13:32that starts with http.
13:34Now you may have other ones in here if you've created other databases, if
13:38you've been to other websites that are using Indexed DB.
13:41It's not likely today, but by the time you're watching this, it may be more likely.
13:45So you're looking for the one that has the domain name of your server that
13:50you're actually using.
13:51It won't be the one that ends in bw.org because that's my server.
13:54It'll be whatever server you're using.
13:56And so I'm going to go ahead and I'm going to delete this file and then I'm
14:01going to start up the browser again. I'm going to kind of hover my handy-dandy
14:04bookmark, go to Chapter 04 and 03- working, and now we get the alert box that
14:10says "Creating the object store."
14:13And that is this alert right here, Creating the object store.
14:17And that means that we're actually creating a fresh object store database.
14:23And now we have have db because after that it goes ahead and does its thing
14:30to get to this point where the dispResults function sees the db object. And I'll say OK.
14:37So now we're successfully creating a new database in Indexed DB.
14:41Creating a new database is probably the hardest part of using Indexed DB.
14:45Once you have a grasp of the use of callbacks and the asynchronous nature of the
14:49model, using it becomes easier.
14:51In the rest of this chapter, we'll be writing a small application using this database.
Collapse this transcript
Adding and reading data in an IndexedDB database
00:00Now that we have an objectStore in our database, it's time to use it.
00:04In this movie we will be writing the code to add and read objects of data in our database.
00:09So here we have the place where we left off in the last movie.
00:13This is 04-working.html.
00:15I am editing it directly on the server and this is a working copy of 04-start.html.
00:21I have also got opened 04-copy.txt and this is the code we'll be copying and
00:27pasting into our working file.
00:30So now the first thing we're going to do is we're going to come down here to
00:34display results, which is really just a stub right now, and we are going to go
00:39ahead and put in the full code for that.
00:42Copy that and select all of this and paste that into place and I am going to
00:50go ahead and indent it. That looks right.
00:57So now there is really quite a bit of code here in the if(db) block.
01:02The first thing it does is it creates an instance of bitable, that's from the
01:08bwH5LS JavaScript file, and that allows us to display the nice results table on
01:15the page. And so it sets a header and it initializes the count.
01:21Now, if you remember in the SQL version of this code, we had a separate routine
01:25for counting the records in a database because that's easy to do in a
01:30relational SQL database.
01:32It's not at all easy to do in a non- relational database, in a key/value type of
01:38a database, and so instead, as we display the rows, we go ahead and count and
01:43then just display that result when we're done displaying the rows.
01:47We then grab our objectStore object from the database.
01:51We do this by starting a transaction and then objectStore itself is a method of
01:56the transaction object and then we grab the objectStore object.
02:01We then set our index, which is a method of objectStore. So you can see how
02:06there is this chain of objects and methods. And then we open a cursor on the
02:13index itself, and that has this onsuccess method and that gets this anonymous function here.
02:20So once we have the cursor open, what a cursor does is it allows you to
02:24step-by-step go through an objectStore object-by-object. And so here's how that works.
02:31The event itself in the event handler has a method of its target the result,
02:38which is the cursor in this case.
02:40So you'll see this pattern a lot. event.target.result.
02:43If we successfully have a cursor, then we traverse the cursor, and if not, then
02:50that just means that we're done.
02:52So for each successful cursor instance the value property of the cursor is the
02:59object, and so I just add a row to the table with v.traveler.
03:03So v is the cursor value.
03:05That's the object from the data store.
03:07v.traveler, v.destination, v. transportation, and then I have got this stub for
03:13the Edit and Delete buttons because we'll get to that in a later movie.
03:16So I've successfully gotten an object and I increase the count because that
03:21gets used for our count.
03:22So we start at 0. Now we have 1. And then I call cursor.continue.
03:27What that does is it then fires this whole event all over again for the next
03:33iteration of the cursor.
03:35So it ends this iteration and it starts the next one.
03:38It's really a loop. It doesn't look like a loop but it really is a loop, and
03:42then when we finally get to the place where we have an empty cursor.
03:45That means that we're done, and when we're done we can display our row count, we
03:49can display our results, and we can set the focus on the travel form.
03:54So before this really do anything we need to actually add some data.
03:58So let's go ahead and get the code that will allow us to do that.
04:03First up is the dbGo function.
04:05I will go ahead on and I will paste that in and we'll just put that right here
04:12after the dispResults function, there it is, and we will indent it and we will
04:20give it a little bit of air between that and the next one.
04:23And then we're also going to want this other function here for resetting the travel form.
04:31We'll just stick that in right after it.
04:36This one is really simple. We will start here, resetTravelForm. This gets used in
04:41a few different places.
04:42So it's broken out as its own function.
04:44All this does is it goes through the travelForm element and this element
04:48function is just a shortcut for getting an element by ID of the HTML.
04:52So here's the form element down here and it goes through that and it just sets
04:59the value to blank for each of these elements within the element, the traveler,
05:03destination, transportation, and key, and make sure that the input action is Add.
05:08We'll see why that is later on and the goButton value is add.
05:13So that just resets the state of the travelForm to put it in a consistent
05:17state between actions.
05:19Now the dbGo, this gets called from the goButton and so inside the form here,
05:26and you will notice I have Word-Wrap on. We have this button and the button says
05:31Add on it and it's named goButton, and the onClick for it is this dbGo function,
05:37and so when you click on that button, it fires this function, and again we check
05:42if there is an error message then there is nothing for us to do.
05:45We grab the form element itself and then we take the value of each of these
05:50elements, inputAction, traveler, destination, transportation, and key.
05:55inputAction and key are these hidden fields down there and those will get
06:00used actually later.
06:02But for now what we do is we take these values, action, traveler, and destination,
06:06we check if somebody has actually put some data in there, and if so, we set up
06:12our current record and our current record is set to this object and it has the
06:16property traveler, destination, transportation. And remember ciTraveler?
06:21ciTraveler is for our index and it's the case insensitive version of traveler.
06:28So it takes the traveler string and it calls the toLowerCase method on that
06:32string to give us a lowercase version, and we can put that in our case
06:36insensitive traveler and it allow us to sort in a casing sensitive method.
06:41So once we have the object, then all we do is insert it into the objectStore
06:47and this is done with this sort of chain of objects and methods.
06:52So the db object has a method called transaction, which starts a transaction.
06:58The transaction is on the oTravel objectStore and it's a read/write transaction,
07:04so this flag is set, and then the transaction object has a method called
07:10objectStore that gets the objectStore object for this particular objectStore and
07:16that objectStore object has a method called Add for adding the current rec.
07:21So we could create this same effect using a bunch of intermediate variables but
07:26there is really no point in it. We can just do it this way.
07:29In fact, sometimes you will see it written with line breaks in between these dots.
07:33And that actually works just fine in JavaScript as well.
07:40So that inserts our object into the objectStore and then we call
07:44resetTravelForm and dispResults.
07:48So let's go ahead and save this and run it in the browser.
07:51I am just going to press Reload here and you will notice that we have our
07:55header tables so we know that we've loaded the code that we just wrote and my
07:59cursor is already up there in Traveler so I am just going to put-in a Traveler.
08:02I will just put in myself. I am going to Ventura to record and I came here on an
08:08airplane and I will press Add.
08:11Now, when I press Add, it goes ahead and it inserts that record into the
08:17objectStore and then it calls dispResults, which goes through the objectStore
08:21and reads all the records and displays them.
08:23So as I add a few more here, I add in Tom and Tom also goes to Ventura, but
08:30he rides a bicycle, and I am going to put in Fred, who is going to London, and he is on a boat.
08:40You will notice that Fred comes up in between because F is after the B and
08:46before the T. Now, if I were to put in another one, say Charlie, and leave it
08:52lowercase and click Add, you see Charlie goes in between.
08:58That's because we're using that case insensitive sort.
09:01So our application is coming together now.
09:03We are successfully adding data to the database and displaying it in a nice
09:07table, and in the next movie we will see how to edit objects in our objectStore.
Collapse this transcript
Editing data in an IndexedDB database
00:00Now we have a working web application that stores data locally on the client
00:03machine using IndexedDB.
00:06In this movie, we'll implement an edit function so that we can change the data
00:10that we've already entered.
00:12Over here in my text editor I've got 05-working.html.
00:16This is a working copy of 05-start.html which is our work so far in this chapter.
00:23I also have 05-copy.text and this is the code that we'll be copying and pasting
00:30so we don't have to type it all.
00:34So the first thing we're going to want to do is put in our Edit and Delete buttons.
00:38Now the Edit button we'll be implementing in this movie and the Delete button
00:42we will be implementing in another movie.
00:44So those will go right here in our display table.
00:48So over here, in our display results, you see we have this little placeholder
00:54and that's where we're going to put the row buttons.
00:56So I'm just going to type the name of the function here.
00:58rowButtons and it gets v.id and v.traveler.
01:07So that's data coming from the objectStore and this is the first time we've used v.id.
01:13Remember this is the key for the key- value storage and when we defined the
01:19database up here, we set the key path as ID and the autoIncrement to true.
01:24So that's automatically getting set.
01:27We're not actually setting that any place.
01:29That's why we haven't seen that before.
01:31So now we're going to go ahead and put in the rowButtons function and that's
01:35just right here. And I'm going to put that in right above this display results
01:43function and all this does, it's just a shorthand.
01:49We could've just put this in line, but it's a little bit easier to do it this
01:53way and I think it's a little more clear to look at.
01:56It's a function that takes ID and traveler and it just returns a string with
02:01those components put into the string.
02:03So there is a form button and its values Edit so that'll display on the
02:08button and its onClick is editGo and it passes the ID and it gets that ID from
02:15right here. And that's the v.id that gets passed in down here in the display results function.
02:22And then there's another button that we'll be using in another movie and this
02:25button is the Delete button.
02:27You'll notice it's onClick is deleteGo and it's got the ID and then a comma and
02:33it has traveler and it has it in quotes and you'll notice I have to use HTML
02:38entities because it's just really, really complicated to put quote marks in a
02:42JavaScript string that's becoming HTML that's becoming JavaScript.
02:46It just gets to be too much of a brain twister and so I just use the HTML
02:51entities, which works great.
02:53Now we need to implement this editGo function and we're going to stick that down
02:58here under dbGo, copy and paste that, and what this does, when you press that
03:12Edit button you want it to feel the form with the data from the database.
03:16So it goes out and it grabs that record from the database and it fills the form.
03:21So it grabs the data, all in this string of object method calls, and so you have
03:27the transaction object that gives you the objectStore object that gives you the
03:32get method and its onsuccess gets set to this event handler.
03:38And so onsuccess of getting that data then you go ahead and you grab.
03:43There is that event target result pattern again and that gives us the record and
03:48in this case the record.traveler is getting set to the travel form element for
03:53traveler, destination to destination, and etcetera, etcetera.
03:57We're setting the goButton to update.
03:59So instead of saying Add it's going to say Update and the inputAction will be
04:04update and we're also setting the key-value to the ID from our record from the database.
04:11We set the focus and select the result in the traveler field.
04:17So that's all very straightforward.
04:18I'm going to press Save and then we need to do one more thing.
04:23So when we press that Update button-- it used to be the Add button, now it's going
04:26to be the Update button--
04:27we're still going to get this dbGo function. And so we want to be able to handle
04:31both types of events.
04:32Right now, it's just handling adding the records to the database, but we want it
04:36to also be able to handle updating record in the database.
04:40So instead of this code here, we're going to cut and paste and something else
04:44and that's this switch statement right here.
04:47So let me just grab this and paste it in and then we'll talk about it.
04:50Now I'll go in indent it the way it's supposed to be indented.
04:57And so what a switch statement does is it takes a particular variable and it
05:02executes different code depending on the value of that variable.
05:05So in this case it's the action value which comes from that hidden form
05:09element and you remember down here in the editGo we're changing that
05:14inputAction to say update.
05:16So when it says update, it will execute this code instead of this code.
05:21This is the code we had in there before and here's the DB transaction
05:27objectStore add and here we're doing something different.
05:30Now there supposed to be a method called Put that works on a objectStore that
05:36will update a particular object in the objectStore and I found that that
05:41didn't work reliably.
05:43So what we're doing instead is we're actually deleting the object and then
05:49adding the new object.
05:51It deletes the old one and adds the new one and I'm finding that this just
05:54works fine and in fact, that may be exactly what Put is supposed to do, because
06:00it makes a lot more sense rather than trying to rewrite a variable record
06:03inside of an objectStore.
06:06So just like in the Add code, we're creating our current record and then we
06:10get our objectStore.
06:13So transaction objectStore gives us our objectStore and then on the objectStore,
06:18we're calling delete by the key and we have our onsuccess function and in our
06:23onsuccess event handler, we're calling add on the same objectStore.
06:28So in this case, we're breaking out this intermediate variable for the
06:31objectStore. We didn't need to do that in the last one because we're only
06:34using it for one thing.
06:36Here we're actually using it for two things.
06:37We're using it for both the delete and the add.
06:40So this ought to be working at this point. I'm going to go ahead and save and
06:44we'll come over here and will press Reload in the browser and there is our four
06:50rows from our last example.
06:52And if I just click on this one that says Charlie here, you'll notice that it
06:57brings it up just as we expect it to and it changes this button from Add to
07:01Update. And I'm just going to type in Charlie with a capital C and I'm going to
07:07click on the Update button and you see that that changes it here in our display.
07:11Now because our display just reads the entire database each time, it just looks
07:17fine and it works exactly as you would expect it to work.
07:20And if I want to edit another one and change say London to Paris, because
07:26of course you can get to Paris by boat, and that works exactly as we expected as well.
07:32So now our application can edit the data in the database.
07:35So all that's left is the ability to delete the data and that will complete the
07:41four basic functions of the database application:
07:43create, read, update, and delete sometimes called crud.
07:47So in the next movie, we'll implement our delete functions.
Collapse this transcript
Deleting data from an IndexedDB database
00:00We now have a database application that creates a database and an object store,
00:04adds data to the object store, displays the data, and can edit the data.
00:09This represents three of the basic four functions of the database application.
00:14When we add the ability to delete data, our application will be complete.
00:18Here I have opened 06 working.html. This is a working copy of 06-start.html from
00:25the Chapter 4 folder of your exercise files.
00:28I also have 06copy.txt open so we can copy and paste rather than having to
00:34type all this stuff.
00:36So the first thing we are going to do is we are going to implement our deleteGo function.
00:41You remember here in our row buttons we have this delete button and it's on
00:47click is the deleteGo function.
00:49And the deleteGo function has two parameters. The first one is the record(id) and
00:55the second one is the Traveler string.
00:58And so we come down here to our editGo function and paste in the deleteGo
01:05right underneath it.
01:06I'll copy that and paste it in and indent it and hit Save.
01:18Now this is a very, very simple function. When the deleteGo button is pressed,
01:25it brings up a confirm box which is kind of like an alert box, but it asks you if it's OK or not.
01:31And if it's OK it calls DB.transaction with the READ_WRITE flag,
01:37.ObjectStore.delete(id) and then it calls reset TravelForm and display results.
01:43And so if we go ahead and run this and reload and if I just press delete
01:50here on this row there, the Charlie row and I get this dialog box, it asks me if
01:56I want to delete or not?
01:57If I say Cancel, nothing happens and if I say Delete, then the record is gone.
02:02Now you notice that we have this resetTravelForm in there and what that
02:07does is it handles the case where I might have pressed the edit button and then I thought "Oh,
02:11I don't want to edit that. I want to delete it." Because the button is right next
02:14to the delete button, it would be an easy mistake to make.
02:17And then if I press Delete, if I didn't have the reset TravelForm function
02:21called there, after I delete it, this data would still be up here in this form
02:26and it would still have the Update and when I click on it, it would still call
02:30the update function and we don't want that.
02:32That can create confusing results.
02:35So instead when I press OK, you notice the form get reset, everything gets
02:39cleared out of it, and the button becomes Add again.
02:42So this is a very convenient little shortcut that allows us to keep our code
02:47clean and keep it working in ways that is not going to confuse the user.
02:50I am just going to add a couple records in here because we are next going to
02:54implement this empty button.
03:03So those are just a few little dummy rows there, because we're going to implement
03:07this Empty button next.
03:09Now if we come down here into the HTML, we will notice that the Empty button is
03:13right here and it calls a function called clearDB.
03:18And so we are just going to grab that function and we are going to drop it right
03:25in here after the resetTravelForm.
03:28And you will notice that this is very much like the delete function.
03:36We use the same confirm box. It says Clear the entire table and then
03:39DB.transaction with the READ_WRITE). objectStore.clear. And so that clear function
03:47just clears all of the data out of the objectStore.
03:50So I am going to save this and will come back in to the browser. We need to
03:55reload first because it doesn't do anything if I don't reload. And I am going to
03:58press that empty button. And Clear the entire table? OK.
04:02And now our table is empty.
04:04I just want to point out a couple of other things here.
04:07You will notice in my editor the word Delete here it's highlighted.
04:11That's because it's actually a key word in JavaScript and this is one of the
04:14odd things about the design of the indexedDB interface is it uses a couple of
04:20method names that are actually reserved keywords, and in some older versions of
04:24JavaScript, if you even load this code up, it's going to give the browser problems.
04:28So that's one. And the other one is the Continue, which you notice doesn't get
04:33highlighted in my editor, but it is actually a reserved word in JavaScript.
04:37That's why in the Safari browser we don't even get the IndexedDB not supported
04:42message, because the JavaScript doesn't load it at all.
04:45Now we have a complete database application that stores its data on the client's computer.
04:49This represents a very powerful capability.
04:52Unfortunately, the web browser market is still very fragmented over client-side
04:57large storage databases.
04:59There is good working support for Web SQL on all browsers except the two largest
05:03desktop browsers, Internet Explorer and Firefox, and while Indexed DB is working
05:08on the latest version of Firefox, it's still in development on all the other
05:12browsers and the specification is still in flux.
05:15So for now if you plan on using Indexed DB, you need to be prepared to have your
05:20application only run on the latest version of Firefox and you need to be
05:24prepared to keep up with the changing specification.
Collapse this transcript
5. Storage Events
Understanding storage events
00:00A DOM storage event is automatically sent when changes are made to a
00:04local storage object.
00:06These events are easy to use and can be useful for updating your screen or
00:12data store when changes are made in another window.
00:14An event is triggered when any of these changes occur in your data set:
00:19a key is added, a key is removed, or a value changes.
00:26The StorageEvent object has a number of properties that are available in
00:29the listening process.
00:31Key is the key that was affected, oldValue is the previous value or null if the
00:38value is new, newValue is the new value or null if a value has been deleted, and
00:45url is the URL of the page that affected the change. storageArea is a copy of
00:52the object from the sending process.
00:55Even though the specification says that StorageEvents apply to both local
01:00storage and session storage, none of the implementations that I've tested send
01:04events when changes are made to a session storage object.
01:08StorageEvents are a useful tool for maintaining contacts between windows running
01:12the same application or related applications on the same domain.
Collapse this transcript
Handling storage events with local storage
00:00The StorageEvent interface is really very simple.
00:03The events are sent automatically, so nothing needs to be done on the sending side.
00:08All you need to do is set up a listener.
00:10Here I've got the Google Chrome browser and I am running this off of my server
00:16because this is one of the things that doesn't work very well with a local file.
00:19This is 02-working.html, which is a working copy of 02-start.html from your
00:25Chapter 5 exercise files.
00:28You will notice I have it running in two tabs.
00:30It's exactly the same URL running in two tabs.
00:35So this is our localStorage example from a previous chapter.
00:39You will notice that one thing that's changed is that there is this
00:42status message here.
00:44It's a paragraph with the message class that says Event status, and that's where
00:49we are going to display status messages about events that are sent and received.
00:54So if I go ahead and enter some data here and I will press the Go button,
01:02you will notice that Traveler, Destination, Transportation, that all gets loaded up
01:06in the database here.
01:07If I look in the other window, there is no change here.
01:10Even though both of these applications are running off the exact same database.
01:14They are exactly the same application and they share a data store because that's
01:18how local storage works.
01:20So if I press Reload here, the data loads up just as we would expect it.
01:25So now we have the same data in both of the windows.
01:28The problem is if I enter some data over here in one window, it changes in
01:38this window but the other window doesn't know that the database has changed.
01:42No event happened that would tell it, oh go, look in your database.
01:46There is different data there now.
01:47You actually have to press the Reload button to get that data to show up.
01:52So we like to accomplish and what StorageEvents are for is to be able to send
01:57a message to all the other windows that are using the same data store and to say, look,
02:01the data has changed. Go ahead and reload it.
02:04In fact, these StorageEvents actually tell you what data has changed.
02:08So if it wanted to be selective and just reload its display for a one
02:11particular thing out of a number of things, you could do that, but in our case,
02:15we are just doing a simple demonstration here, so that you can get an idea of how this works.
02:19So we are going to do it the simple way and just reload the data.
02:22So let's go ahead and make this happen.
02:25Here I have the same file loaded up in my text editor and you will notice this
02:28is loaded off of the server.
02:29You can tell it by the ridiculously long file path up at the top there.
02:34Again, this is just our example from the Local Storage chapter earlier.
02:39One thing you'll notice is different, down here at the bottom we have this
02:42paragraph. It's class message, id eventResult and it says Event Status.
02:49That's this paragraph right here with a nice little brown border on it.
02:53So the first thing we are going to want to do is we are going to want to get our
02:56event listener and just like with so many things, we want to check first to make
03:01sure that the event listener is present before we go and load it.
03:07So paste in this code here.
03:09Over in this other window, I have my 02- copy.txt from the exercise files where
03:14you can cut and paste, so we don't have to type all of this.
03:17I am just going to go ahead and indent that nicely.
03:20This works just like our other places where we've done this in this course.
03:24It checks to see if window has addEventListener and if it does, it returns that.
03:28And we will go ahead and we will put that in a variable. And that will call this
03:41function here and here it returns the EventListener object and it will sign its
03:47results to variable.
03:48That way we can use the variable while checking to make sure that it's actually
03:52present before we go and grab it.
03:55Now, once we set up our event listener, which we have not done, yet but once we
03:59have set up our event listener we are going to want to update that status
04:03message on the screen.
04:05So here in our copy.txt we have the eventStatus function and this is a nice
04:12little function for displaying our status.
04:20So all this does is if we have a string, it'll go ahead and update the
04:25eventResult element. It's using this element function from my bw Local Storage
04:32JavaScript library here.
04:36All that does is it calls getElementById. It's just a nice little shortcut and
04:41it sets the innerHTML to the value of the string.
04:44If there is no string, it just says Event status with a colon like that.
04:48So that's really straightforward.
04:50Now, finally, we want to set up our event handler.
04:53So, the way this happens is we first set up a function to do what needs to be
04:59done when we get an event and I will put that in right there.
05:03And so this function eventHandler, it gets an event object and that event object
05:09has a number of properties.
05:09It has a URL. It also has the storageArea and the storageArea has all of the data.
05:15It also has the before and after data that's been changed.
05:19But the storageArea is what we are going to be concerned about right now and so
05:23we're going to take the traveler and the destination and the transportation.
05:27Now, the reason for this is if we were to instead use the new value property,
05:32it would only give us one at a time and that actually becomes cumbersome for us to
05:36use in our particular use case.
05:39You actually get a separate event for each value that changes and so we are
05:44really getting three separate events here because three values are changing.
05:49So rather than handle those individually, which can be a little bit cumbersome,
05:53we are just looking at the storageArea object, which gives us the actual storage
05:58area from the sending window.
06:00In other words, the window that had changes happened, it sends this event, and
06:04along with it, it sends the whole object and so that way we've got all these
06:08properties at once and we can show them all at once.
06:11Then we'll just call dispResults, which we will reload from the
06:14database and show our nice little table.
06:16So, this all actually works really smoothly and well.
06:21Finally, we need to set up the event handler. In our initialization function down
06:27here in, init display(initDisp), we are going to just pop-in this code here and
06:32it checks to see if we have the addEventHandler object and if we do, it goes
06:37ahead and it calls it and it sets up the event handler.
06:42So it gives the name of the data store, which is called storage and that's a
06:47common name for the local storage object.
06:50You will always use that string.
06:52That's not dependent on anything in your code. And then the eventHandler.
06:56And this false over here is just because we are not using a capture mode that
07:01has to do with the way that events cascade in the DOM tree.
07:05It's not something that you need to use at this point.
07:08So this actually sets up our eventHandler as the recipient of the events.
07:15Then finally, here in dbGo when we press the button, we want to set up a
07:21call to our eventStatus and all this does is it clears the eventStatus when
07:27we change some data so that string doesn't stick there and confuse the situation.
07:32So, I am going to go ahead and press Save and we will go and reload our example
07:37in both of these windows and then we will enter some data here.
07:42So if I enter Bill, Ventura, by Car, and press Go, so this is what we expect in
07:50our sending window, and then over in our receiving window, you notice that we
07:54got the event triggered message.
07:57There is our data, Bill, Ventura, Car.
08:00This is the URL of the sending window. It could actually be a different page in
08:06the same application and then you would know which one it is. And you notice
08:10that our data got updated there in our window.
08:12So now both of our windows have the same data in them.
08:15Likewise, if I go and change something over here and press Go, you see our
08:26Event status clears.
08:27That actually helps to reduce confusion when you're doing an application like
08:31this that's asynchronous.
08:32And you'll notice our data gets updated over here and then in the other window,
08:36which is now the receiving window, the data got updated there as well.
08:41Here's the data and the URL of the sending page.
08:45So as you can see, it's really simple to implement an event listener for a local
08:50storage application and using storage events can be a simple way to enhance the
08:55functionality of your application.
Collapse this transcript
6. Offline Applications
Overview of offline web applications
00:00Using HTML5's Offline Web Applications specification, you can make your
00:05application available for use when the browser is not connected to the network.
00:10The full specification is available on the World Wide Web Consortium's web site
00:14but it's really very simple.
00:16It all starts with a cache manifest file.
00:19This file should end in .manifest, and it should have a MIME type of
00:25text/cache-manifest.
00:28This file lists the files that are required for offline operation.
00:31Its presence triggers the browser to cache the listed files.
00:36The cache manifest file must begin with the words cache manifest and the file
00:41may have any of 3 sections.
00:44The CACHE section lists the files that must be cached.
00:47This is the default section if no section header is specified.
00:51The NETWORK section lists the files that must not be cached and the
00:56FALLBACK section lists files that will be used in place of resources that cannot be cached.
01:03There is also an ApplicationCache object that keeps track of the progress of the cache update.
01:08It can be used for notification, but for most applications you won't really need it.
01:14The Offline Application specification can be very useful when combined with a
01:18simple local storage JavaScript application.
01:22This will allow you to provide rich data -enabled applications that can continue
01:26running without network connectivity.
Collapse this transcript
Using applications offline
00:00To use your web storage application offline, you'll need to create an
00:04offline manifest file.
00:05The offline manifest file is very simple to create.
00:09You'll notice here I have our sessionStorage example from an earlier chapter.
00:14I have added an image to it.
00:16This is the Explore California logo from the Explore California web site that's
00:20used in a lot of the HTML5 courses here at lynda.com.
00:25And there's a reason that I added that logo to this page and we'll see that in a little bit.
00:29I have got the page itself loaded up on my server.
00:32I have all of these files loaded on my server.
00:35This is one of those things because we are talking about online/offline,
00:38it's a whole lot easier to work with if you're using a remote server.
00:42You can do this with a local server.
00:44It's just a lot more challenging.
00:46It's a lot easier to develop with a remote server.
00:48So I've loaded these up on my server and I'm using the Google Chrome browser here.
00:53This protocol for the offline application's manifest file works in all the major
00:59browsers except Internet Explorer.
01:01But I find that the Google Chrome browser is the easiest one for the development work.
01:06I like the way their console works.
01:08Safari also has a console that's almost exactly the same and Firefox actually
01:13has a couple of bugs in their offline application implementation
01:18that make it a little bit difficult to do the development work in Firefox.
01:22So I'm using Google Chrome for this purpose and over here in my text editor I
01:26have a working copy of 02-start.html, which I've named sessionStorage.html.
01:33I also have a working copy of 02 -start.manifest, which is named
01:37sessionStorage.manifest, and I have my .htaccess file for my server.
01:42All of these files are being edited in place on the server.
01:45The sessionStorage.html file, the 02- start.html file, is just our sessionStorage
01:52example from an earlier chapter.
01:54With this one addition down here you'll notice that I've added this image
01:59source, this exp-calif-logo.gif, because we'll be using that in our example a
02:06little bit later on here.
02:07Now it's a good idea to make sure that your web server is sending the right MIME
02:12type for your manifest file.
02:14If you're using Apache server this is very simple to do.
02:17You just create a .htaccess file in the exact same folder as your application.
02:23You may already have a .htaccess file and all you have to do is add this line to it.
02:28AddType and the MIME type which in this case is text/cache-manifest and the file
02:35name extension and here it's .manifest.
02:38If you're using another type of this server, you'll need to figure how to do
02:41that or ask your system administrator to do that for you.
02:44The bottom line is you want the correct MIME type.
02:47Now, if you can't actually make that happen it may still be okay.
02:51Most of the browsers will try to figure out what a file's MIME type is from the
02:56file name extension.
02:57So just make sure you're using .manifest for your manifest files as I am here.
03:03Now before we go and set up the manifest file in our HTML file, I'm going to
03:07switch back over here to the browser and show you what happens when I take this offline.
03:11So with it online I press Reload, I get my application.
03:15You'll notice it's got some data in there.
03:17I'm just going to unplug my network cable.
03:19That's the easiest way to take this thing offline and there we go.
03:23The network cable is now unplugged, and I'm going to press Reload and you notice
03:27I get this lovely Google Chrome message telling me that it can't connect to the
03:31Internet and there's nothing showing up in my logs here.
03:34So we'll plug it right back in and now it should be plugged back in, give it
03:38just a moment for the operating system to figure that out, and I'll press Reload
03:42and there we have our application back.
03:45Now I'm going to come over here into my HTML file and I'm going to put the
03:49manifest in, and all I have to do here in my HTML tag, out at the end I'm going
03:55to put in an attribute called manifest and I'm going to put the file name of
04:01the manifest in here.
04:07Let's save that and that will load up this manifest file which has these files in it:
04:13the manifest itself, the HTML file, my CSS file, and my JavaScript file.
04:18Those are the essential things.
04:19You'll notice that I did not include the image file.
04:23So when we load that in offline mode we ought to get a broken image.
04:26I'm going to switch back to my browser and before I unplug the cable I want
04:31to make sure I reload it so it's got its manifest and you'll notice down
04:35here in my log that it's loading the manifest file and it's loading the files from the manifest.
04:40So creating application cache with manifest. There is our manifest file and
04:45there is our four items from the manifest file:
04:48the CSS, HTML, the manifest file itself, and the JavaScript.
04:53If we come back over here and look at the manifest, those are the four files in there.
04:58So now we can unplug the cable again and when I press Reload you'll notice that
05:04it reloads the application and it can't find the logo file.
05:08And so that did not get loaded because it wasn't listed in the manifest.
05:12So anything that you don't list in the manifest is not going to be available offline.
05:16You notice that my application still works. I can type in some data here and
05:24press Go and my application is working just fine.
05:28It's just not loading that image.
05:30So we're going to do something a little bit different with the image.
05:33Let's go ahead and plug the cable back in.
05:36I'll press the Reload button.
05:38So at this point the Google Chrome browser seems to still be confused about the image itself.
05:42We'll ignore that for now because we're going to fix it anyway.
05:45I'm going to come back over here to my manifest file and I'm going to add a section.
05:50I'm going to add a FALLBACK section and this will tell the browser what to do
05:54when it can't find that image.
05:56So the image itself is called exp-calif-logo.gif.
06:04So the first parameter in the FALLBACK line is the file that it would
06:08otherwise be looking for and the second parameter is the file that you're
06:11going to use instead.
06:13So it's going to be exp-calif-logo-offline.gif.
06:19Now I'm going to take that filename and I'm going to put it in my cache.
06:25That will make sure that that file actually gets cached.
06:31I've saved this. I pressed Ctrl+S to save it.
06:34Now I'm going to come back over to the browser and press Reload again and you
06:38notice that it reloads the cache itself.
06:41And it makes sure that all of these files are cached.
06:43Again, it's got the offline version of the GIF file, but not the online version.
06:48So let's go ahead and unplug the cable and I'll press Reload and you notice we
06:51get the offline version of the image.
06:55So in our images I'm just going to go ahead and show you this Exercise Files
06:59folder. Press Preview here.
07:01So that's the regular version of the logo and then the offline version of the
07:06logo is the same image as with this offline image, so it will shade it out.
07:10And so that's the image that we're seeing here in offline mode in the browser.
07:14So let's go ahead and plug the cable back in.
07:16I'm just going to press Reload and there we have our original image back there also.
07:22Chrome just got confused there for a moment about whether that particular image
07:25was online or offline.
07:27It's important to note here that all of this stuff is still pretty experimental
07:32in all of the browsers.
07:33All the browsers have little quirks as to how they deal with offline
07:37storage. All of the browsers have little quirks with how they deal with the application cache.
07:42It's just going to take a little bit of patience to work with this and you'll
07:45notice that they all work a little bit differently as well.
07:49So I like to use Chrome to set it up and to get it all working fine, and then in
07:53the other browsers it's going to work as well as it's going to work.
07:56So now we have our application and it works online.
07:59I'm just going to enter some different data here.
08:09And you see that that's working.
08:12If we take it offline, unplug the cable and press Reload, we've got our offline
08:18version of the image and the application is still working. We still have our
08:22local data there and I'll put in some different data and press Go and that's
08:30still working and we can plug it right back in.
08:34I'll press Reload, it brings up our image, and our data is still there and the
08:38application is still working.
08:40You can see that using a JavaScript- based web application offline is made simple
08:46with the offline application's manifest file.
08:49But you can also see that the testing cycle for offline applications can be
08:53a little bit tricky, and the implementations are still in their alpha or
08:57beta quality stages.
08:59But it's a simple thing to do.
09:01The manifest file itself is a fairly simple format and all you really have to do
09:06in your application itself is to add the manifest attribute to your HTML.
09:12So that's how you take your web application offline using the offline
09:16application's manifest file.
Collapse this transcript
7. Conclusion
Goodbye
00:00In this course, my goal was to give you a good understanding of the new features
00:04available with HTML5 for storing data locally on the client machine.
00:09Many of these features are still experimental or in flux at this time, but
00:13it's good to get some experience with them now, so that you can start using
00:17them as they become stable.
00:19The local storage features available with HTML5 represent a great opportunity to
00:24create new web applications with features and capabilities that haven't been
00:28available on the web until now.
00:30It's my sincere desire that this course will give you a foundation in these
00:34emerging technologies, so that you can take full advantage of these new features
00:39as they become available for wide deployment and use.
Collapse this transcript


Suggested courses to watch next:

HTML5: Structure, Syntax, and Semantics (4h 34m)
James Williamson

HTML5: Geolocation in Depth (34m 19s)
Bill Weinman


HTML5: Drag and Drop in Depth (1h 0m)
Bill Weinman

HTML5: Video and Audio in Depth (2h 7m)
Steve Heffernan


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 98,718 instructional videos.

start free trial learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 1,899 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.


site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked