Reputation: 4423
Consider a web page that has a select menu with a JavaScript event handler tied to the menu's onchange event that when fired reloads the page with a new query string (using the value selected in the menu).
Issue: when the user hits the Back button, the page DOM is restored from the cache but NOT the state of the select menu.
Browsers affected: Firefox and Safari (which use a back/forward cache)
Example:
<script language="javascript" type="text/javascript">
function reloadPage() {
var menu = document.getElementById("select1");
var val = menu.options[menu.selectedIndex].value;
window.location.href = 'test.html?select1=' + val;
}
</script>
<form action="#" method="get" name="form1">
<select name="select1" id="select1" onChange="reloadPage();">
<option value="A" selected>Option A</option>
<option value="B">Option B</option>
<option value="C">Option C</option>
<option value="D">Option D</option>
</select>
</form>
View this page and notice that option A is selected. Then select a different option (say option C) - the page is reloaded (with a query string, ?select1=C). Then hit the Back button - the select menu continues to show Option C as selected.
Question: Does anyone know why the select menu isn't restored and how one could solve this issue? I've used JavaScript in the past to force the form fields on a page to match the query string but there are issues with that approach (i.e., FF and Safari don't normally execute the onload event for the window when loading a page from the cache) and it seems like a hack to me.
Any suggestions?
Update: It has just occurred to me that what might be going on is the following:
So I think this isn't an issue of the browser not restoring the state of the select menu, it's an issue of timing.
Upvotes: 23
Views: 24049
Reputation: 399
Going a bit further with a plain-vanilla Javascript implementation based on the approaches of @juanlu and @Mitch, consider this update which makes use of the pageshow event:
window.addEventListener(\"pageshow\", function() {
[... document.getElementsByTagName("SELECT")].forEach(function (select) {
let selectedOption = select.querySelector("option[selected]");
if (selectedOption) select.value = selectedOption.value;
});
});
Upvotes: 0
Reputation: 3
As of January 16, 2020 I had a very similar issue and was unable to find a solution on Stackoverflow.
Here is what fixed this issue for me:
Update Jquery!
I updated from an older version (2.x) to 3.4.0. I went with this version since I am running bootstrap 3 and newer versions of Jquery completely break bootstrap 3 any higher than 3.4.0.
I hope this saves some people some time.
Upvotes: 0
Reputation: 2033
This is what happens by default in forms (not just selects): the browser will keep the last values. I wouldn't add any JavaScript code to alter this behavior unless you want to debug that code with multiple browsers.
The easiest solution, that would fix the problem in most (all?) modern browsers, is to use autocomplete="off"
in the <form>
tag.
Edit: See answer https://stackoverflow.com/a/14421723/1391963
Upvotes: 10
Reputation: 408
Here is a vanilla JS version of @Mitch's answer.
let selects = document.getElementsByTagName('select');
for (let i = 0; i < selects.length; ++i) {
let currentSelect = selects[i];
let selectedOption = currentSelect.querySelector('option[selected]');
if (selectedOption) currentSelect.value = selectedOption.value;
}
Here is the performance comparison
Upvotes: 4
Reputation: 1554
The snippet from @frakhoffy worked for me, but broke normal select behavior in Chrome. When hitting the page without a selected option, the select was blank even though there is not a blank option in the select. I ended up going with:
$(document).ready(function () {
$('select').each(function () {
var select = $(this);
var selectedValue = select.find('option[selected]').val();
if (selectedValue) {
select.val(selectedValue);
} else {
select.prop('selectedIndex', 0);
}
});
});
Upvotes: 15
Reputation: 950
This jQuery code did the trick for me
$(document).ready(function () {
$("select").each(function () {
$(this).val($(this).find('option[selected]').val());
});
})
Upvotes: 31
Reputation: 16035
AFAIK the reason it's not being restored is that DOM isn't the one that was in the cache at the last time of cache-loading. The browser restores what the cached-object was on page-back. You have to maintain state yourself.
I would suggest putting a function in the body proper that will always run as the DOM is parsed (but I've not got a sample environ setup to test this scenario so I'm going on my "it should work" detector)
<script type="javascript">
function fix_selects(){
//do something here to ensure that the select is setup how you want.
//Maybe using a window location hash?
}
fix_selects();
</script>
Upvotes: 2