Last week I was at KCDC and it was absolutely amazing. I was lucky enough to not only attend, but also to speak about something near and dear to my heart – Offline First techniques. This time I was talking about using IndexedDB.

I’ve written about the importance of offline availability here. Offline First offers a kind way to handle a user’s loss of connection – something over which they have little to no control. And even more than that – implementing Offline First techniques can help people, which I’ve written about here.

Before we dive into any code, let’s talk about IndexedDB’s structure. I think IndexedDB is more similar to NoSQL, rather than traditional relational SQL. So let’s delve into how IndexedDB data is stored.

Each web app can have multiple IndexedDB databases, which are made up of Object Stores. An Object Store is kind of like a table, but it doesn’t use columns. It’s a place to store Objects, which will probably look similar to a server response or ajax request. Later on, we’ll look at some examples.

Within an Object Store, there are Indexes. An Index is a defined property within an Object Store. It’s a little bit like a column, except that it doesn’t have a defined type, nor does it require a type.

Indexes have various properties which can be applied to them. A few common ones include autoIncrement, unique, and keyPath. When we apply autoIncrement to an Index, the Index will create something similar to an auto-incrementing ID in SQL. I mentioned before that Indexes don’t have type requirements, but every rule needs an exception. When we use autoIncrement our Index will always be a number. However, we don’t need to specify a type for this to happen, nor do we need to pass in a number, as IndexedDB is going to handle that for us.

Another handy property we can apply is unique. unique allows us to specify whether or not an Index value can be duplicated. So for instance, if we wanted a list of email addresses, we might say that the email Index would be unique. This would keep any duplicates from being added. In the event that someone tries to add an email that is already in our Object Store, the email (and associated record) won’t be added. This helps protect the integrity of the data.

The last property we’ll discuss here is keyPath. The keyPath property allows us to define a sort of “master” Index within our Object Store. It’s a little similar to a primary key in a SQL table, but like most Indexes, does not require a specified type. Defining an Index as a keyPath allows us to look up records directly by that property.

Using our email example from before, if we specified the email address Index as our Object Stores keyPath, we could look up “ceo@bigdealcompany.com” directly, and get that record. If the keyPath for a record were a name instead, we would need to look up “Patricia CEO” to find the email address. Specifically, we cannot directly look up records via an Index that has not been defined as a keyPath.

Now that we have a good idea of IndexedDB’s structure, we’ll look at some code in the next post.


Earlier today I was lucky enough to speak at 200OK in Tulsa. My talk, Mapping The Internet, is about a project I’ve been working on called MargieMap.

MargieMap is a visualization of United States census tracts by income. It also layers libraries on top of the census tracts. I used Mapbox to host the map tiles. The income data comes from the U.S. Census Bureau and the library data came from the Institute of Museum and Library Services.

I’m planning to open source the data I’ve gathered, but I haven’t found a suitable (read: affordable) way to do that yet.

Why income?

I’ve been interested in the correlation between income and internet access for a long time. A lack of Internet Access contributes to the Homework Gap.

Of course a lack of internet access isn’t limited to households with school-aged children, nor are it’s challenges. According to a 2015 Pew Research Study nearly 20 percent of adults in the United States are smartphone-dependent – meaning they do not have access to the Internet outside of their smartphone.

These individuals reported using their phone for a multitude of things including job searches and looking up medical conditions. A large number of these individuals also reported losing their cell phone data due to cost.

With internet access being so prevalent, it’s hard for some developers to imagine not having connection, but the truth is – everyone will lose connection. Losing connection is something that is almost completely beyond a person’s control. Unfortunately, it’s usually beyond the control of the person when they’ll regain their connection.

Why libraries?

Free wifi is a very common feature for restaurants and coffee shops, but the truth is that wifi isn’t really free. Patrons of the establishment are expected to buy things in order to hang out and use the wifi.

Public libraries are one of the few places a person can go and use the internet without having to pay for a meal or a drink – which is really important if someone is unemployed and searching for jobs online. There are so many reasons why someone might need to use the internet – to research an illness, pay bills, or research for school. Fortunately, public libraries offer internet access without a fee.

How can I use the map?

The map has categorized incomes by color – low incomes are heavy blue and fade as the median income increases. Higher incomes start off light and turn into a heavy pink. You can search by zip code, city, or state and see the incomes in that area. If you click on an area on the map, you’ll see the median individual income for that tract.

You might also notice orange dots scattered around the map – those are public libraries. The goal of the map was to visualize the income data along with libraries and see if there’s any correlation between income and libraries.

What’s next?

I’ve gotten data for all 50 states onto the map, but I also have data for U.S. territories as well. I plan to map the income data for the territories, but I’ve been struggling to find a list of libraries for the territories. If you know where I could find this data, please let me know!

Starting small, I’d like to find high/low incomes for the country, and for each state as well. Once I have that, I’ll be able to focus on those income tracts and see if they have libraries and how many.

There’s so much I want to do with this data – MargieMap is just the first step. I’m very excited to see what all I learn, and I’ll be sure to blog about it too!

** I would be remiss if I didn’t mention all the help I got from Devin Clark. Devin is a JavaScript dev with a specific interest in geo and mapping, and he was a great resource on mapping tools. Thanks Devin! **


Note: This is a pretty old post, which didn’t include the most fully-featured version of a beginner service worker. If you’re looking for a better getting started post, I recommend checking out this post.

Service Workers are a super cool bit of tech that allows your user’s browser to cache files and assets. Why is this so cool? Because eventually your user will lose connection. What happens then? Without something to bridge the gap between the time user loses connection and the time they regain connection, your user is just out of luck.

But no more! Service workers are here to help bridge the gap (at least in certain browsers). With the browser caching the files and images you choose, your user can continue using your site until the connection comes back.

To start using a service worker you’ll need some JavaScript for your application, as well a service worker file. I’ve created a demo Let’s get started!

Step One: Register your service worker

Registering your service work is very simple. The code looks like this:


if(navigator.serviceWorker) {
  navigator.serviceWorker.register('service-worker.js');
}

The above code would go in your application’s JavaScript file. All it’s doing is letting the browser know to go ahead and register that service worker. Be sure to wrap your register function in an if-statement because cross-browser support for service workers isn’t quite there yet.

Step Two: Install your service worker

This code lives in your service-worker.js file:


// service worker
self.oninstall = function() {
  caches.open('cash').then(function(cache) {
    cache.addAll([
      'index.html',
      '/img/my-image-name.jpg'
    ]);
  });
};

Service workers expose certain events, including oninstall and fetch. The method above opens a cache in the browser and adds files to the cache. This way, if your app goes offline, the browser already has files and can load them in. Another benefit of this is speeding up your site’s response time. Since the files are cached, the browser no longer needs to serve files from a remote server. This ends up giving your users a great performance increase.

Step Three: Specify what happens on fetch

This code also lives in your service-worker.js file:


// fetch function
// called when connection is lost
self.onfetch = function(event) {
  // this will grab the very last request
  event.respondWith(caches.match(event.request));
};

Note: This step was not a part of the original post.

Step Four: Handle for requests that aren’t in your cache:


// fetch function
// called when connection is lost
self.onfetch = function(event) {
  // this will grab the very last request
  event.respondWith(
    caches.match(event.request)
    .then(function(cachedFiles) {
      if(cachedFiles) {
        return cachedFiles;
      } else {
        fetch(event.request);
      }
    })
  );
};

This is the function that will be called when your files need to be fetched. When files are cached, they are saved like a stack. Older caches are closer to the bottom, with newest caches being on top. The above function will grab the latest cache and send that to the browser where it can be rendered.

And with that, you’re done! You can grab this code and run it in a server (I like to use https-server). Once you stop the server, you can refresh the page and see your site is still there! Pretty cool, huh?


I was fortunate enough to spend a weekend at Offline Camp in Oregon this month. It was wonderful!

I’ve been really passionate about offline accessibility for a long time, although I’ve only recently learned it has a name: Offline First. Right around the time I learned that, I also had the opportunity to attend Offline Camp and meet a whole bunch of like-minded people. Spending the weekend with lots of socially-conscious individuals and brainstorming ways Offline First can help underprivileged individuals is one of the best ways to spend a weekend.

I’ve talked about the importance of reliable internet access here and here, but I’ll briefly summarize the idea of Offline First.

Offline First is a practice which considers the inevitable – what will happen when your web app goes offline? Offline First knows that your app will at some point go offline, so the idea is to put technology into place to help when that happens.

Additionally, there are many people who live their lives offline. In a world of online services, how can the needs of underprivileged people be met? Offline First attracts many people who are interested in how to help with this problem, and at camp we spent a lot of time talking about what we can do to help.

We talked about using Service Workers to cache online pages in the user’s browser. This would help users move from an online to an offline state, and back again. And we also talked about the future of Electron and Service Workers and how these two technologies work to achieve the same goals. Mesh networks came up in discussion time and again as a potential solution for providing internet access in remote locations.

One of my favorite discussions was talking about the economics of Offline First. I genuinely believe that the only way we’ll get Offline First into the wider consciousness of developers is if we can make a solid business case for it. We focused on making a business case for this and I’m super excited about what comes next from that.

We weren’t focused on Offline all the time though. Some of the best parts were from Passion Talks. Passion Talks are short, five-minute talks about anything you’re passionate about. I really enjoyed getting to know my fellow campers better through hearing about their interests.

Overall, I’d say attending Offline Camp was one of the best decisions I made in 2017. I learned so much, and I’m so hopeful for the future of offline. Many thanks to the organizers who put the camp on: Steven, Gregor, Bradley, and Teri. I know putting camp on was a lot of hard work, but I so appreciate you for doing it.

Note: Offline Camp offers scholarship opportunities for campers. If you’re able to help, it could be life-changing to the scholarship recipient. If you find that you’d like to attend camp, but need assistance, I would highly recommend contacting the organizers.


More than 10 percent of Americans are without home internet. As such, it’s really important to be considerate of users with inconsistent internet. A user is without internet is effectively stuck on an island, unable to communicate with the outside world.

One of the simplest things we can do is check for network connection. To do this we can use: navigator.onLine. This function – which is built into the JS spec and also has great cross-browser compatibility – returns a boolean value based on whether or not the user has a network connection. It might look like this:


if(navigator.onLine) {
  console.log("User is online!");
} else {
  console.log("User is not online. :(");
}

This is really handy because we can test for this before running any ajax calls and offer the user a much nicer experience because they won’t lose connection and suddenly hit a bunch of connection errors.

We can set up an event listener and continuously monitor network connection.


window.addEventListener('offline', function(event) {
  console.log("We are offline! :(");
});

window.addEventListener('online', function(event) {
  console.log("We are online! :)");
});

While no network connection will mean you are not on the internet, a true value can be misleading. Just because you are on a network doesn’t mean you have internet connection – for instance you can be on an internal network but the network doesn’t have an external internet connection. This might return true.

So what can we do to test if our true is actually true? If we get true, we can test if we can access an image.


fetch('some/img/url/here').then(
    function(response) {
      console.log(response);
    })
    .catch(function(err) {
      console.log(err);
    });

And when we look at the response, we can see the status code. If you have no connection, the catch will return your error with something like TypeError: Failed to fetch.

And there you have it! You can check for network connection with navigator.onLine, and to be sure you are truly online, you can use fetch to pull an image and check the status code.