Bill
Bill

Reputation: 4423

Select menu not being restored when Back button used

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:

  1. option C is selected
  2. the page is cached
  3. the JavaScript loads the new URL
  4. hit the back Button
  5. option C is restored because it is what was cached prior to the JavaScript/page reload.

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

Answers (7)

Lorin Thwaits
Lorin Thwaits

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

Christopher
Christopher

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

Pere
Pere

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

juanlu
juanlu

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

enter image description here

Upvotes: 4

Mitch
Mitch

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

Frank Hoffman
Frank Hoffman

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

jcolebrand
jcolebrand

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

Related Questions