Friday, September 5, 2014

Micro-solution: Preserving input values against all odds (JavaScript)


The problem: How do you keep the already entered values of HTML inputs if you can't control when the containing document is closed or reopened?

In my case, I am developing a browser extension which requires a configuration popup with some input fields. The user is expected to enter several values into the fields and there is a specific “Save” action, which performs an authentication check etc. I can process button presses etc — yet the popup itself (with all of its HTML, CSS and JavaScript) may be brutally closed by the browser without any prior notifications.

For example, if the user clicks outside of this popup on the browser toolbar — bang! — the popup is dead. Our favourite user then re-opens the popup — and all the data they lovingly typed in — gone.

So I need a simple method to store and repopulate input fields without any additional user action.

Solution

Start with the code:
// Preserve real-time inputs data in case popup is closed externally
// Set input event monitoring
$('input').on('input', function(){
 var popInputs = appAPI.db.get('popup_inputs') || {};
  
 popInputs[$(this).attr('id')] = $(this).val();
 
 // Using Crossrider local DB - could be localStorage
 appAPI.db.set('popup_inputs', popInputs);
});

// Populate the inputs with pre-stored values
// Retrieve the stored values from whatever you saved them to
var storedInputs = appAPI.db.get('popup_inputs');
 
if(storedInputs) {
 Object.keys(storedInputs).forEach(function(prop) {
  if(storedInputs[prop])
   $('#' + prop).val(storedInputs[prop]);
 });
}

The answer consists of two parts.

First, we set watch for “input” events on our input controls (you may want to narrow it down with IDs and classes, I have no such need since I only have three inputs). Surprisingly, this works for every button stroke, and even for pasting text into the fields.

This the current value of the field is then saved in your preferred storage, as part of an “popup_inputs” object, that just contains input values for each element ID. Nice and simple.

Note that I am using this in Crossrider API context (it is a nice framework for creating browser extensions), so for convenience I use their local storage. You may use browsers localStorage instead, or whatever means you prefer.

Second, when our form is rendered, I check for presence of stored input values, and, enumerating the stored object's own properties (Object.keys(your_object) is really handy for this!), populate the inputs with their values — our property names are input IDs, so they're really easy to find now.

And. It. Works.

I'll appreciate any feedback and comments.

Photo by Eunice

2 comments:

  1. Do not forget to clear the popup_inputs when you processed them.

    ReplyDelete
    Replies
    1. Yup, that's a good point and I do clear it when "Save" is pressed! Well noted :)

      Delete