こんにちはフロントエンドエンジニアのまさにょんです!
今回は、JavaScriptでsessionStorageやlocalStorageを活用してReloadしてもデータを保持する方法について解説していきます。
目次
sessionStorageやlocalStorageを活用して、データを保持する方法
以前、47都道府県の複数選択と検索が可能なSelectboxをJavaScriptで作成しました。
今回は、そのSampleCodeを機能拡張して、データを保持する仕組みを導入したいと思います。
要件定義・仕様
- Serverから受信した optionDataから動的に、SelectBoxを作成する
- 検索で、動的にSelectBoxを再作成する
- SelectBoxで選択したOptionは、画面に表示される
- 複数選択が可能である
- 選択したOptionは、選択状態を解除することができる
- Reload(再読み込み)時もデータを保持するような仕組みを導入する
- 今回は、sessionStorage を活用する
47都道府県の複数選択と検索が可能なSelectboxを作成するSampleCode全文
<style>
/* 入力フォーム */
input[type='text'] {
width: 80%;
height: 30px;
margin-top: 10px;
border-radius: 8px;
}
/* セレクトボックス */
#select-pref {
width: 80%;
}
/* Defaultのボタンのスタイルを無効化する */
.btn {
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
padding: 0;
appearance: none;
}
.btn {
background: #eee;
border-radius: 3px;
justify-content: space-around;
align-items: center;
margin: 20px 10px;
max-width: 280px;
padding: 10px 25px;
color: #313131;
transition: 0.3s ease-in-out;
font-weight: 500;
}
.btn:after {
content: "";
position: absolute;
top: 50%;
bottom: 0;
right: 2rem;
font-size: 90%;
display: flex;
justify-content: center;
align-items: center;
transition: right 0.3s;
width: 6px;
height: 6px;
border-top: solid 2px currentColor;
border-right: solid 2px currentColor;
transform: translateY(-50%) rotate(45deg);
}
.btn:hover {
background: #6bb6ff;
color: #FFF;
}
.btn:hover:after {
right: 1.4rem;
}
</style>
<body>
<h1 style="text-align: center;">日本 47都道府県</h1>
<div style="text-align: center;">
<p>好きな都道府県を5つまで、選択可能です</p>
<!-- Select-Box -->
<div>
<select name="pref" id="select-pref">
</select>
</div>
<!-- 検索-Box -->
<div style="margin-top: 12px;">
<span>検索</span>
<input type="text" id="searchbox">
</div>
<!-- 検索ボタン・リセットボタン -->
<span>
<input type="button" id="search" class="btn" value="検索">
<input type="button" id="reset" class="btn" value="リセット">
</span>
<!-- 選択中のものが表示される -->
<p>選択されたものが表示されます (ボタンを押すと選択が解除されます)</p>
<div id="disp-select">
</div>
</div>
<script>
// sessionStorageを活用して、Reloadしてもデータを保持する仕組みを作る
// JavaScriptで複数選択と検索が可能なSelectboxを作成する
// [ 実行-Task-List ]
// 1. Serverから受信した optionData から動的に、SelectBoxを作成する
// 2. 検索で、動的にSelectBoxを再作成する
// 3. SelectBoxで選択したOptionは、画面に表示される
// 4. 複数選択が可能である
// 5. 選択したOptionは、選択状態を解除することができる
// [ 今回、実装する追加機能 ]
// 1. Reloadや、送信に失敗してもデータを保持するような仕組みを導入する
// 2. 今回は、sessionStorage を活用する
// 選択肢・Optionの作成と追加を実行する関数
function OptionCreator (selectPrefBox, optionList, optGroupList) {
optionList.forEach((opt, index) => {
// 1. 最初は、<option value="">選択してください</option> を作成する
if (index == 0) {
let option = document.createElement('option');
option.setAttribute('value', '');
option.innerText = '選択してください';
selectPrefBox.appendChild(option);
}
let option = document.createElement('option');
option.setAttribute('value', opt.id);
option.innerText = opt.value;
let groupId = opt.groupId;
let belongToGroup = document.getElementById(`${groupId}`);
// 所属するoptgroupがなかったら、追加する
if (belongToGroup == null) {
const belong = optGroupList.find(group => group.id == groupId);
selectPrefBox.appendChild(belong);
belongToGroup = document.getElementById(`${groupId}`); // 再度、取得する
}
belongToGroup.appendChild(option);
});
}
function NoMatchOption (selectPrefBox) {
let option = document.createElement('option');
option.setAttribute('value', '');
option.innerText = '検索に該当はありません';
selectPrefBox.appendChild(option);
}
// SelectBoxを作成する関数
function SelectCreator (selectPrefBox, optionList, optGroup, searchList, searchBool) {
if (optionList.length == 0) return;
selectPrefBox.innerHTML = ''; // 初期化処理
// 1. グループ・カテゴリを作成する
// optgroupタグを作成 => グループカテゴリを作成する
const optGroupList = optGroup.map((group) => {
let optgroup = document.createElement('optgroup');
optgroup.setAttribute('id', group.id);
optgroup.setAttribute('label', group.value);
return optgroup;
});
// 2. 選択肢・Optionの作成と追加
if (searchList.length !== 0 && searchBool) OptionCreator(selectPrefBox, searchList, optGroupList);
else if (!searchBool) OptionCreator(selectPrefBox, optionList, optGroupList);
else NoMatchOption(selectPrefBox);
}
// [ 1. Serverから受信した optionData から動的に SelectBoxを作成する ]
// 1-1. Serverから受信した、DataSet
const optionData = [
{id: null, value: 'group@北海道'},
{id: 1, value: '北海道'},
{id: null, value: 'group@東北'},
{id: 2, value: '青森県'},
{id: 3, value: '岩手県'},
{id: 4, value: '宮城県'},
{id: 5, value: '秋田県'},
{id: 6, value: '山形県'},
{id: 7, value: '福島県'},
{id: null, value: 'group@関東'},
{id: 8, value: '茨城県'},
{id: 9, value: '栃木県'},
{id: 10, value: '群馬県'},
{id: 11, value: '埼玉県'},
{id: 12, value: '千葉県'},
{id: 13, value: '東京都'},
{id: 14, value: '神奈川県'},
{id: null, value: 'group@中部'},
{id: 15, value: '新潟県'},
{id: 16, value: '富山県'},
{id: 17, value: '石川県'},
{id: 18, value: '福井県'},
{id: 19, value: '山梨県'},
{id: 20, value: '長野県'},
{id: 21, value: '岐阜県'},
{id: 22, value: '静岡県'},
{id: 23, value: '愛知県'},
{id: null, value: 'group@近畿'},
{id: 24, value: '三重県'},
{id: 25, value: '滋賀県'},
{id: 26, value: '京都府'},
{id: 27, value: '大阪府'},
{id: 28, value: '兵庫県'},
{id: 29, value: '奈良県'},
{id: 30, value: '和歌山県'},
{id: null, value: 'group@中国'},
{id: 31, value: '鳥取県'},
{id: 32, value: '島根県'},
{id: 33, value: '岡山県'},
{id: 34, value: '広島県'},
{id: 35, value: '山口県'},
{id: null, value: 'group@四国'},
{id: 36, value: '徳島県'},
{id: 37, value: '香川県'},
{id: 38, value: '愛媛県'},
{id: 39, value: '高知県'},
{id: null, value: 'group@九州沖縄'},
{id: 40, value: '福岡県'},
{id: 41, value: '佐賀県'},
{id: 42, value: '長崎県'},
{id: 43, value: '熊本県'},
{id: 44, value: '大分県'},
{id: 45, value: '宮崎県'},
{id: 46, value: '鹿児島県'},
{id: 47, value: '沖縄県'},
];
// 1-2. Group-配列 => {id: 'group_1', value: '北海道'}[]
const optGroup = [];
let groupCount = 1;
let groupId = '';
// 1-3. 47都道府県データに、groupを紐づける
// {id: 1, value: '北海道', groupId: 'group_1'}[]
const optionCustom = optionData.filter((opt, index) => {
// グループ・データなら、加工して、optGroupに投入する
if (/^group@/.test(opt.value)) {
groupId = `group_${groupCount}`;
groupCount++;
opt.id = groupId;
opt.value = opt.value.replace("group@", "");
optGroup.push(opt);
} else {
opt.groupId = groupId;
return opt;
}
});
console.log({optionCustom});
console.log({optGroup});
// 1-4. SelectBoxを取得する
let selectPrefBox = document.getElementById('select-pref');
// 1-5. 初期のSelectBoxを作成する
SelectCreator(selectPrefBox, optionCustom, optGroup, [], false);
// [ 2. 検索で、動的にSelectBoxを再作成する ]
// 検索のための入力フォームを取得する
const searchbox = document.getElementById('searchbox');
let searchResult = []; // 検索結果のOption-List
// inputイベントで検索の入力文字列を受け取って、検索結果の配列を作成する
searchbox.addEventListener('input', (e) => {
let searchStr = e.target.value; // 検索文字列
searchResult = optionCustom.filter((pref) => { // 検索文字列から絞り込む
if (/^group@/.test(pref.value)) return false;
// 正規表現で変数を使用するためには、RegExp-Classを使用する
let reg = new RegExp(`${searchStr}`); // 部分一致
// 検索文字列のパターンと、登録データがマッチするかでTestをする
return reg.test(pref.value);
});
console.log({searchResult});
});
let searchBtn = document.getElementById('search'); // 検索ボタン
// 検索ボタンに、clickイベントを追加する => searchResultで SelectBoxを作成する
search.onclick = () => SelectCreator(selectPrefBox, optionCustom, optGroup, searchResult, true);
// [ 3. SelectBoxで選択したものは、画面に表示される => 複数選択が可能である ]
// 3-1. 選択中のものを表示するInput-Boxを取得する
let dispDiv = document.getElementById('disp-select');
// 3-2. SelectBoxに changeイベントを追加する
selectPrefBox.addEventListener('change', (e) => {
// 選択してくださいは、弾く!
if (!e.target.value) return;
// 1. 上限を5つまでにして、それ以上は、弾く!
if (6 <= dispDiv.childElementCount + 1) {
alert('選択できる数は、5つまでです');
return;
}
// 2. valueにidを付与している
const id = Number(e.target.value);
// 3. 選択済みの都道府県は、弾く!
const idList = [...dispDiv.children].map(btn => btn.id);
console.log({idList});
if (idList.some(i => Number(i) == id)) {
alert('選択済みです');
return;
}
// 4. 該当の optionデータを取得する
const option = optionCustom.find(opt => opt.id === id);
console.log(option);
// 5. セッションストレージから、データを取得する
let selectedOptionState = sessionStorage.getItem('selectedPrefList');
console.log({selectedOptionState});
if (!selectedOptionState || selectedOptionState.length == 0) {
// 5-1. null または 文字列の長さ0の時は、最初の追加
sessionStorage.setItem('selectedPrefList', option.id);
} else {
// 5-2. @で区分けして、IDを追加して更新する
sessionStorage.setItem('selectedPrefList', `${selectedOptionState}@${option.id}`);
}
// 5. input-btn を作成して、optionのデータを紐付ける
let input = document.createElement('input');
input.setAttribute('type', 'button');
input.setAttribute('id', option.id);
input.setAttribute('value', option.value);
input.classList.add('btn');
// 6. 選択を解除する機能を作成した input-btn に付与する
input.onclick = e => {
let id = e.target.id;
console.log({id});
let selectedOptionState = sessionStorage.getItem('selectedPrefList');
console.log({selectedOptionState});
let reg = new RegExp(`${id}`); // 部分一致
console.log({reg});
if (reg.test(selectedOptionState)) {
// selectedPrefListから、該当IDを削除して、更新する
sessionStorage.setItem('selectedPrefList', selectedOptionState.replace(`${id}`, ""));
}
dispDiv.removeChild(e.target);
}
// 7. 選択されたoptionを input-btnとして画面に表示する
dispDiv.appendChild(input);
});
// [ 4. 検索状態をResetする機能を作成する ]
// 4-1. 検索・リセットボタンを取得する
let resetBtn = document.getElementById('reset');
// 4-2. 検索・リセットボタンに、clickイベントを追加する
// SelectBoxの optionをリセットする
resetBtn.onclick = () => SelectCreator(selectPrefBox, optionCustom, optGroup, [], false);
// [ 5. セッションストレージの内容を確認して、選択済みのものは、画面に表示する ]
let initSelectedPrefList = sessionStorage.getItem('selectedPrefList');
// console.log({initSelectedPrefList});
if (initSelectedPrefList) {
// 5-1. @で区切っているIDの配列を作成する
let idStateList = initSelectedPrefList.split('@');
// console.log({idStateList});
if (idStateList) {
idStateList.forEach(id => {
// 5-2. IDが空文字でなければ、画面に追加する処理をする
if (id.length) {
const option = optionCustom.find(opt => opt.id == Number(id));
let dispDiv = document.getElementById('disp-select');
let input = document.createElement('input');
input.setAttribute('type', 'button');
input.setAttribute('id', option.id);
input.setAttribute('value', option.value);
input.classList.add('btn');
input.onclick = e => {
let id = e.target.id;
let selectedOptionState = sessionStorage.getItem('selectedPrefList');
let reg = new RegExp(`${id}`); // 部分一致
if (reg.test(selectedOptionState)) {
sessionStorage.setItem('selectedPrefList', selectedOptionState.replace(`${id}`, ""));
}
dispDiv.removeChild(e.target);
}
dispDiv.appendChild(input);
}
});
}
}
</script>
</body>
JavaScript書籍 Ver. 中級-上級者向け
JavaScript書籍 Ver. 初級者向け
Twitterやってます!Follow Me!
神聖グンマー帝国の逆襲🔥
神聖グンマー帝国の科学は、世界一ぃぃぃぃぃぃ!!!!!