Your Development & Design Resource
Web Storage Introduction for the Notes Domino Developer
04/15/2020 by Chris Toohey
[ Banner Source Photo by JOSHUA COLEMAN on Unsplash ]
With support as far back as Internet Explorer 8, it's a mystery why using Web Storage hasn't become a standard practice for IBM Notes Domino application developers. Perhaps it's an unfamiliarity with the browser-based persistent storage solution or - for those of you familiar with the name - stringValue architecture - you might not consider the direct correlation with the methods most XPages developers use daily.
Either way, after this article you'll fully understand what Web Storage is and how you can use it in your own development efforts.
What is Web Storage
key=value either for the particular browser window session (as sessionStorage) or as persistent storage (as localStorage). You might want to compare Web Storage to Web Browser Cookies... but there are rather big differences that may direct you to using one over the other:
Cookies data storage limits are 4Kb of data per site, whereas Web Storage allows - depending on the browser - from 5MB to 25MB per site.
Cookies allow local persistence as well as tabbed persistence for the session. Web Storage allows local persistence or window/tabbed persistence for the session. This means that you can open a second instance of the application in a new window/tab and have an entirely unqiue scope for your sessionStorage!
You can set a Cookie to expire. You can create/delete Web Storage.
That's the short list, but it establishes a base understanding of Web Storage.
How to use Web Storage
Web Storage (unlike HTML5 storage options IndexedDb or File API) is available in almost every browser and release including Internet Explorer 8. Yeah, even those of you stuck supporting IE8 in your corporate environments can use this. IE8ers can't use much else at this point, but they can use localStorage and sessionStorage. This almost universal availability allows us to write code that works today and - based on it's adoption - shows no sign of deprecation.
In other words, this isn't some new trick or cool hack - it's an established feature that's available in every browser and client out there (except in Opera Mini for some reason). To confirm availability, here's a list of browsers and versions supporting Web Storage.
Before we dive into how we use Web Storage, let's first take a look at how we can access SessionStorage and LocalStorage from various browsers. I'd recommend having your browser-specific DevTools open when we get into the use cases and demos.
- (Google Chrome) View And Edit Local Storage With Chrome DevTools
- (Mozilla Firefox) Manage local site storage settings
- (Microsoft Internet Explorer) Microsoft Edge DevTools > Storage
As for actually using Web Storage, it's really simple.
First, let's create an entry in our sessionStorage:
Now, let's read our sessionStorage entry:
And if we want to delete the entry:
Web Storage can only store strings. If you try to store another data type, most browsers will do their best to convert that data type to a String. For example:
... will actually store
You can, however, manipulate the results:
For multiple value storage, you can use JSON parsing (here's a list of browser and versions supporting JSON parsing... which is basically every one - even Opera Mini...). To use multiple values, you'll just need to
.parse() your values.
And if I wanted to use my "activeFilters" again as an array:
JSON.parse(sessionStorage.getItem("activeFilters")); //returns Array ["keyword1", "keyword2", "keyword5"]
You can pretty easily manage this storage as-needed:
So now that we have an understanding of how we can use Web Storage... how do we actually use Web Storage?!
Web Storage Use Case
Let's create a use case for both localStorage and sessionStorage.
The first use case that comes to mind for localStorage is Application Preferences. Most Domino web application developers tend to overlook a feature like localized Application Preferences, opting more for a User Profiles-based approach. Application Preferences are different however, as it refers more to customizing the user experience for that particular client vs. a set of preferences or settings that should "follow" the user across clients and devices.
For inspiration, let's look to mobile device applications. Most mobile device applications for web service-based solutions have both a server-stored set of preferences for the particular user (your account/profile) and your device-specific preferences (settings). Are there any applications that you use within your organizations that would benefit from server-stored preferences and device-specific settings? While you're thinking about that, let's crank out a demo...
localStorage Demo: Application Preferences
Let's say you have a dashboard which acts as the default view for your application. In other words, when the user opens your application, they're given the dashboard. That's a fairly common design standard. What is not so standard - at least with most XPages applications I see - is the ability to customize this dashboard to meet the preferences of the given user.
In this demo, we'll allow you to store a "username" so the application can properly greet you.
This "username" will be stored in the browser localStorage and available during the active session, across any number of tabs that you have open for the given session, and will remain in the browser's localStorage memory until it is replaced with another value or cleared (either via code or browser preferences).
sessionStorage Demo: Filters and Tabs
Because sessionStorage persists for the life of the window accessing the origin domain [HTTP protocol, subdomain/domain], sessionStorage gives us reliable window-scoped variables. For an XPages developer, the idea of a scoped variable isn't new. We have 4 scopes for our variables: requestScope, viewScope, sessionScope, and applicationScope. While extremely powerful, there are use cases where those scopes don't quite deliver. So let's create a simple scenario that often creeps into far too many XPages-based applications:
You have a simple database with a large number of document. You want to create a simple "filter" that your user can apply to both the active view as well as any other views they open until they either clear the filter or exit the application. Most of us would bind the "filter" to a sessionScope variable, and for most uses, that's the right call.
But once the application is in production and the user starts actually using it, we hear the same general complaint.
Most users, when they get their filtered results, will open a second (or third, or fourth) tab in their browser and either want to view unfiltered or differently-filtered results and compare them against their original filtered results. If you're using a sessionScope variable for your filtering, then it won't work while still allowing fluid interaction in the previous tab (eg., loading the next page of results would recalculate the filter, changing the results, etc.). Using viewScope would give you this functionality... but it would break the ability to apply your filter to multiple views.
You can work around this by passing a queryString parameter back and forth between your views, but that could be problematic for various reasons (try maintaining the same queryString parameter across multiple pages, making sure any/all links to a different page transfer the queryString parameters, etc.). You could also store a complicated mess in sessionScope based on originating pages getting a "key", and simply applying that "key" to grab the sessionScope variable that contains the correlating filter... but you run into the same problem as the queryString.
A sessionStorage-based filter would give you locally-accessible stored filters (remember, neither of these storage options can be read by the server), and we can use those filters for the life of that window and only that window: all additional tabs would have their own sessionStorage scope!
Now, instead of writing out a view, writing out different filters, and writing a demo that shows how you can apply and persist those filters for the lifetime of the given browser window/tab... we're going to simply the demo to illustrate how it's done.
So in this demo, we're going to "enable" one out of three tabs as an active tab. The active tab will stay "active" for the life of the window/tab unless another tab is selected/set to "active", or the sessionStorage is cleared (either by code or browser preferences).
Again, there's little difference between a "filter" in this context and an "active" tab, and this demo has been simplified to illustrate the mechanics of sessionStorage vs. cluttering up said demo with view grids and filtering options.
You can view the demo - which is a Page Design Element with contents set to "text/html" here:
-- feel free to copy/paste this as an HTML page or a Page Design Element set to "text/html" in a NotesDatabase of your own and play around.
There are tons of use cases for localStorage and sessionStorage... but don't trick yourself into using it because you read this article. For every problem there is a preferred solution.
I've found that the localStorage persistent data model is great for Roku-style user device authorization. Simply put, instead of having to "log in" a specific device, you login via your phone or request an "authorization code" via email. Once you receive that code, you enter it into the device so you can "authorize" said device. The device submits the "authorization code" to the server via an Anonymous request, and the server grants a token string that's stored in localStorage. Now, when you open the site from that device, it checks in the token from localStorage onLoad and the target application recognizes that - for my device - Chris Toohey is using the app.
In other words, I made the Scorm Player much more scalable and improved concurrent user usage by only committing Scorm progress data when the user is leaving the training or closing the window instead of issuing a collection of HTTP Posts on each slide transition, button click, or other interaction within the Scorm packages.
So as I said, there are tons of use cases for localStorage and sessionStorage. I've demoed two and discussed two more. I'm certain at this point (for those of you still reading, thank you), that you have an idea or two where you can use these design options to address a given need in one of your development projects. If not, at least you're now familiar with Web Browser storage... or specifically familiar with how localStorage and sessionStorage work.
For bigger tasks, there's indexedDB and Manifests... but that's for another article.