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