6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

input系要素の状態を一時的にsessionStorageに保持

Last updated at Posted at 2021-04-14

input/select/textarea各要素の状態を一時的にsessionStorageに保持し、ブラウザをリロードしたり別ページから戻って再表示した時に保持しておいた状態を各要素へ反映させ状態回復するものです。

####スクリプト####

input_retention.js
'use strict';
{
    const
        // 保持対象要素CSSセレクター
        cssSelectors = {
            // checked系
            checked : [
                        'input[type=checkbox]',
                        'input[type=radio]',
                      ].join(),
            // value系
            value   : [
                        'input[type=text]',
                        'input[type=password]',
                        'input[type=datetime-local]',
                        'input[type=date]',
                        'input[type=time]',
                        'input[type=month]',
                        'input[type=week]',
                        'input[type=number]',
                        'input[type=email]',
                        'input[type=range]',
                        'input[type=search]',
                        'input[type=tel]',
                        'input[type=url]',
                        'textarea',
                        // type属性を持たないinput要素(text扱い)
                        'input:not([type])',
                      ].join(),
            // selected系
            selected:   'select',
        },

        elements = {},
        storage  = {
            key : location.pathname + ':inputElementRetention',
        };

    window.addEventListener('DOMContentLoaded', function() {
        if(checkStorage(storage.key + '_c') !== true) return;

        storage.data = sessionStorage.getItem(storage.key);
        storage.data = storage.data !== null ? JSON.parse(storage.data) : {};

        // 対象要素取得・イベントリスナー追加・storageデータを各要素へ反映
        // checked系
        elements.checked = document.querySelectorAll(cssSelectors.checked);
        for(let i = 0; i < elements.checked.length; i++) {
            const e = elements.checked[i];
            e.addEventListener('change', storageSet);
            if(storage.data.checked !== undefined) e.checked = storage.data.checked[i];
        }

        // value系
        elements.value = document.querySelectorAll(cssSelectors.value);
        for(let i = 0; i < elements.value.length; i++) {
            const e = elements.value[i];
            e.addEventListener('input', storageSet);
            if(storage.data.value !== undefined) e.value = storage.data.value[i];
        }

        // selected系
        elements.selected = document.querySelectorAll(cssSelectors.selected);
        for(let i = 0; i < elements.selected.length; i++) {
            const e = elements.selected[i];
            e.addEventListener('change', storageSet);
            if(storage.data.selected !== undefined) {
                for(let l = 0; l < storage.data.selected[i].length; l++) {
                    e.options[l].selected = storage.data.selected[i][l];
                }
            }
        }
    });

    // 各要素の状態取得・storageに保持
    function storageSet() {
        // checked系
        storage.data.checked = [];
        for(let i = 0; i < elements.checked.length; i++) {
            const e = elements.checked[i];
            storage.data.checked[i] = e.checked ? 1 : 0;
        }

        // value系
        storage.data.value = [];
        for(let i = 0; i < elements.value.length; i++) {
            const e = elements.value[i];
            storage.data.value[i] = e.value;
        }

        // selected系
        storage.data.selected = [];
        for(let i = 0; i < elements.selected.length; i++) {
            const e = elements.selected[i];
            const selectedArray = [];
            for(let l = 0; l < e.options.length; l++) {
                selectedArray.push(e.options[l].selected ? 1 : 0);
            }
            storage.data.selected[i] = selectedArray;
        }

        sessionStorage.setItem(storage.key, JSON.stringify(storage.data));
    }

    function checkStorage(str) {
        try{
            sessionStorage.setItem(str, str);
            sessionStorage.removeItem(str);
            return true;
        }
        catch(e) {
            return false;
        }
    }
}

####使用法####

保存したい要素のあるHTMLに

<script src='input_retention.js'></script>

を追記します。
ページロード時に対象要素をすべて拾って動作を適用しますので、それ以外の設定はありません。
簡易的な処理なので、対象外にしたい要素の個別指定などはありませんが、例えばtype=passwordは保持したくない、というような場合は

value   : [
            'input[type=text]',
            'input[type=password]',
            'input[type=datetime-local]',

から'input[type=password]',を削除、という形で対応できるかと思います。

また、別スクリプトで動的に要素が増減するようなページでは、動的に増えた要素にはイベントリスナーがかかっていなかったり、保持しているデータと要素の配置が変化したりするので想定通りの動作は期待できないかと思います。

####使用例####

設定デモ

<!DOCTYPE html>
<html lang='ja'>
<head>
    <meta name='viewport' content='width=device-width,initial-scale=1'>
    <meta charset='utf-8'>
    <title>input系要素 sessionStorage保持サンプル</title>
    <script src='input_retention.js'></script>
    <style>
        textarea {
            width: 300px;
            height: 100px;
        }
    </style>
</head>
<body>
checkbox<br>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<br>
radio(nameなし)<br>
<input type='radio'>
<input type='radio'>
<input type='radio'>
<br>
radio(nameあり)<br>
<input type='radio' name='a'>
<input type='radio' name='a'>
<input type='radio' name='a'>
<br>
text<br>
<input type='text'>
<input type='text'>
<br>
password<br>
<input type='password'>
<br>
日時系<br>
<input type='datetime-local'>
<input type='date'>
<input type='time'>
<br>
<input type='month'>
<input type='week'>
<br>
number<br>
<input type='number'><br>
email<br>
<input type='email'><br>
range<br>
<input type='range'><br>
search<br>
<input type='search'><br>
tel<br>
<input type='tel'><br>
url<br>
<input type='url'><br>
type無し(text扱い)<br>
<input><br>
select(single)<br>
<select>
    <option value='0'>------</option>
    <option value='1'>aaaaaa</option>
    <option value='2'>bbbbbb</option>
    <option value='3'>cccccc</option>
</select>
<br>
select(multiple)<br>
<select multiple>
    <option value='0'>AAAAAA</option>
    <option value='1'>BBBBBB</option>
    <option value='2'>CCCCCC</option>
    <option value='3'>DDDDDD</option>
</select>
<br>
textarea<br>
<textarea></textarea><br>
<textarea></textarea>
</body>
</html>

sessionStorageですので、保持されたデータはブラウザを閉じた時点で消えます。
同一ページを別タブで開いた場合は別データ扱いになります。
どんな形式で保持しているかは、Chromeの場合であればデベロッパーツール(F12キー等で開きます)のApplication > Storage > Session Storage > 該当オリジン から確認してみてください。

location.pathname + ':inputElementRetention' のキーのものが該当データです。
location.pathnameをキー名に含めているのは、複数ページで使用した場合にページ単位でストレージデータを使い分けられるようにするためです。

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?