Я пытаюсь сохранить и восстановить состояние checkbox
и других элементов, используя localStorage
, когда пользователь дублирует или закрывает вкладку. Это работает хорошо, когда у меня есть только checkbox
, но как только я добавляю дополнительные элементы, состояние checkbox
не сохраняется правильно в Chrome и Edge. Вдохновленный аналогичной проблемой, обсуждавшейся здесь, я создал версию, демонстрирующую проблему:
function save() {
var checkbox = document.getElementById('checkbox1zaal1');
var textarea = document.querySelector('textarea');
localStorage.setItem('checkbox1zaal1', checkbox.checked);
localStorage.setItem('box', textarea.value);
}
function load() {
var checked = JSON.parse(localStorage.getItem('checkbox1zaal1'));
document.getElementById("checkbox1zaal1").checked = checked;
document.querySelector('textarea').value = JSON.parse(localStorage.getItem('box'));
}
function wis() {
location.reload();
localStorage.clear();
}
load();
<input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()" />
<input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()" />
<input type = "checkbox" id = "checkbox1zaal1">
<textarea>Hello, world!</textarea>
Действия по воспроизведению проблемы:
Флажок на вкладке дубликатов не установлен.
Что мне не хватает? Это известная ошибка в Chrome и Edge, или есть другой подход, который я могу попробовать, чтобы гарантировать, что состояние checkbox
сохраняется правильно вместе с другими элементами?
🤔 А знаете ли вы, что...
С JavaScript можно создавать интерактивные формы и проверять введенные пользователем данные.
ДОБАВЛЯТЬ :
var as = document.getElementById('textbox').value
//Code to sent to discord webhook
sent(as)
Я выполнил шаги, которые вы предоставили, чтобы воспроизвести проблему, но это не воспроизвело ее. Но когда я отключил настройку «Разрешить сайтам сохранять и читать данные cookie (рекомендуется)», я смог воспроизвести проблему. Поэтому введите «edge://settings/content/cookies» в адресной строке Edge и проверьте, не отключен ли этот параметр, чтобы вызвать эту проблему.
В вашем коде есть одна серьезная проблема: вы используете JSON.parse
, фактически JSON.stringify
не обрабатывая значения, которые вы пытаетесь проанализировать позже. Это приводит к ошибке при попытке проанализировать значение textarea
. Эту ошибку легко увидеть, открыв инструменты разработчика Chrome...
Поэтому я бы посоветовал исправить ваш load
, избавившись от JSON.parse
.
function load(){
var checked = localStorage.getItem('checkbox1zaal1') === "true";
document.getElementById("checkbox1zaal1").checked = checked;
document.querySelector('textarea').value = localStorage.getItem('box');
}
Но даже после исправления этой ошибки она по-прежнему не работает должным образом (по крайней мере, в браузерах на базе Chrome. Работает с Safari). Однако не знаю, почему это не удается, потому что (по крайней мере, для меня) происходит сбой только при начальной загрузке на новой вкладке. Т.е. если я сделаю «Обновить» на вновь созданной вкладке, она будет работать как положено.
Но я смогу заставить его работать, если сделаю
setTimeout(load, 0)
вместо
load();
Похоже, это какая-то проблема с синхронизацией или состояние гонки в движке браузера. Может быть, кто-то с большим пониманием сможет дать здесь объяснение. Используя setTimeout
, мы фактически больше не вызываем load
синхронно в процессе рендеринга, а только после завершения рендеринга. Кажется, здесь есть разница...
Также кажется странным, что флажок на вкладке «Дублировать» на самом деле снят, потому что, если я полностью удалю вызов load
, «Дублировать вкладку» восстановит значения входных данных, как если бы они были на вкладке источника ... Так что, возможно, это конфликт/проблема времени между восстановлением входных значений с помощью операций «Дублировать» и обновлением входных данных из сценария. Это предположение также может объяснить, почему все работает так, как ожидалось, если выполнить «Обновить» на дублированной вкладке. И что еще более странно, это также работает, если textarea
не пуст при сохранении или когда я полностью удаляю textarea
и весь связанный с ним код...
Так что, вероятно, это не тот канонический ответ, который вы ищете. На мой взгляд, это больше похоже на ошибку в Chrome (и производных браузерах, таких как Edge или Brave). Тем более, что он работает так, как и ожидалось, в браузерах, отличных от Chrome, таких как Safari или Firefox, а также работает в браузерах на базе Chrome, когда вы обновляете или просто вставляете URL-адрес в новую пустую вкладку. Возможно, это даже зависит от версии и/или версии ОС, потому что она вполне работает и для других пользователей в Chrome. Вы можете попробовать сообщить о проблеме в Chromium (но я предлагаю сначала исправить ошибки с помощью JSON.parse
)
Проблема:
Вы пытаетесь сохранить и восстановить состояние флажка вместе с другими элементами, используя localStorage. Хотя он работает только с флажком, введение дополнительных элементов (например, текстовой области) может привести к тому, что состояние флажка не будет правильно сохраняться в Chrome и Edge при дублировании вкладок.
Причина:
Между рендерингом браузера и вашим кодом JavaScript существует состояние гонки. Когда вы загружаете данные из localStorage (с помощью функции загрузки), браузер может отображать такие элементы, как текстовая область, прежде чем устанавливать ее значение. Это может перезаписать сохраненное состояние флажка в localStorage, когда вы позже вызовете функцию сохранения.
Решение:
Есть два подхода к решению этой проблемы:
Использование setTimeout:
Оберните вызов функции загрузки внутри setTimeout с задержкой 0. Это гарантирует выполнение загрузки после завершения рендеринга браузера:
function load() {
setTimeout(function() {
var checked = localStorage.getItem('checkbox1zaal1') === 'true'; // No need for JSON.parse for booleans
document.getElementById("checkbox1zaal1").checked = checked;
var textarea = document.querySelector('textarea');
textarea.value = JSON.parse(localStorage.getItem('box'));
}, 0);
}
Использование события хранения:
Прослушивайте событие хранения объекта окна. Это событие срабатывает всякий раз, когда изменяется localStorage. Вы можете проверить изменения в конкретном ключе, который вы используете для флажка, и соответствующим образом обновить его состояние:
window.addEventListener('storage', function(event) {
if (event.key === 'checkbox1zaal1') {
var checked = event.newValue === 'true'; // No need for JSON.parse for booleans
document.getElementById("checkbox1zaal1").checked = checked;
}
});
load();
Дополнительные баллы:
Вы можете напрямую использовать localStorage.setItem('checkbox1zaal1', checkbox.checked) для хранения логических значений (проверенное состояние) в localStorage. Не забудьте очистить localStorage, когда пользователь явно удаляет данные (с помощью кнопки «Удалить»).
Я не уверен, что это известная ошибка, но это ошибка со стороны Chrome. Я предполагаю, что это связано с тем, что эта duplication
функция не стандартизирована, и, очевидно, их метод борьбы с дублированием все еще не завершен.
Итак, прибегнем к обходным путям!
<body>
<input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()">
<input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()">
<input type = "checkbox" id = "checkbox1zaal1">
<textarea>Hello, World!</textarea>
<script>
// Treat this as a constant, in real app, you can use `const`
// We're now limiting ourselves to es5
var CHECKBOX_NAME = 'checkbox-' + Math.random().toString().substring(2, 8);
var DEFAULT_TEXTAREA_VALUE = 'Hello, World!';
function save() {
var checkbox = document.getElementById('checkbox1zaal1');
var textarea = document.querySelector('textarea');
if (checkbox.checked) {
localStorage.setItem('checkbox1zaal1', '1');
} else {
localStorage.removeItem('checkbox1zaal1');
}
localStorage.setItem('box', textarea.value);
}
function load() {
var textarea = document.querySelector('textarea');
textarea.value = localStorage.getItem('box') || DEFAULT_TEXTAREA_VALUE;
var checkbox = document.getElementById('checkbox1zaal1');
checkbox.name = CHECKBOX_NAME;
localStorage.getItem('checkbox1zaal1') === '1' &&
checkbox.setAttribute('checked', 'checked');
}
function wis() {
location.reload();
localStorage.clear();
}
load();
</script>
</body>
Очевидно, использование другого флажка name
for позволяет браузеру правильно загрузить значение. Не волнуйтесь, хотя мы создаем флажок name
динамически выше, мы все равно можем отслеживать его, используя постоянный идентификатор.
Н.Б. Взял на себя смелость провести рефакторинг, систематизировать и устранить некоторые ошибки синтаксического анализа.
Вот попытка -
function load() {
var checked = JSON.parse(localStorage.getItem('checkbox1zaal1'));
if (checked) {
document.getElementById("checkbox1zaal1").click();
}
document.querySelector('textarea').value = JSON.parse(localStorage.getItem('box'));
}
Вместо установки атрибута checked
мы вызываем щелчок, чтобы они проверили этот элемент!
Н.Б.
setTimeout
для выполнения load
— такой же хороший обходной путь, как и следующий!:) Очень распространенная проблема с vanilla js. Нам нужно подумать о трёх вещах. Изменение пользовательского интерфейса, изменение СОСТОЯНИЯ, а также сохранит ли пользователь это состояние или нет.
Поэтому я немного обновил ваш код. Пожалуйста, дайте мне знать, если вам нужно больше объяснений, кроме комментариев.
<!doctype html>
<html lang = "en">
<head>
<meta charset = "utf-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1">
<title>Unsaved Checkbox State with localStorage in Chrome and Edge - Labground</title>
<link rel = "icon" href = "/images/lab.svg" type = "image/svg+xml">
</head>
<body>
<input type = "button" id = "ReserveerButton1" value = "save" onclick = "save()">
<input type = "button" id = "Wisbutton1" value = "delete" onclick = "wis()">
<input type = "checkbox" id = "checkbox1zaal1">
<textarea></textarea>
<script>
const DOM_ELEMENTS = {
checkbox: document.getElementById('checkbox1zaal1'),
textarea: document.querySelector('textarea')
}
const EL_STATE = {
checkbox: JSON.parse(localStorage.getItem('checkbox1zaal1')),
textarea: localStorage.getItem('box')
}
function wis() {
localStorage.clear();
location.reload();
}
// Save
function save() {
localStorage.setItem('checkbox1zaal1', DOM_ELEMENTS.checkbox.checked);
localStorage.setItem('box', DOM_ELEMENTS.textarea.value);
}
// Onload function.
(function() {
// Get checkbox state
if (EL_STATE.checkbox === null) {
EL_STATE.checkbox = false;
localStorage.setItem('checkbox1zaal1', EL_STATE.checkbox);
} else {
localStorage.setItem('checkbox1zaal1', EL_STATE.checkbox);
}
// UI checkbox state
DOM_ELEMENTS.checkbox.checked = EL_STATE.checkbox;
// Get textarea state
if (EL_STATE.textarea === null) {
EL_STATE.textarea = 'Hello World!!!';
localStorage.setItem('box', EL_STATE.textarea);
} else {
localStorage.setItem('box', EL_STATE.textarea);
}
// UI textarea state
DOM_ELEMENTS.textarea.value = EL_STATE.textarea;
// Listen on changes of the checkbox UI and UPDATE state each time the checkbox is change
DOM_ELEMENTS.checkbox.addEventListener('click', (event) => {
EL_STATE.checkbox = event.target.checked;
});
// Listen on changes of the textbox UI and UPDATE state each time the value is change
DOM_ELEMENTS.textarea.addEventListener('input', (event) => {
EL_STATE.textarea = event.target.value;
});
})();
</script>
</body>
</html>