Click here to Skip to main content
15,890,123 members
Articles / Web Development / HTML5

Having Fun with HTML 5 History API – Part Two

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
18 Jul 2016CPOL2 min read 4.2K   1  
Having fun with HTML 5 History API – part two
<g:plusone count="false" href="http://blog.andrei.rinea.ro/2016/07/18/having-fun-with-html-5-history-api-part-two/" size="small">

As we saw earlier in part 1, hitting the back button into a page with filled in fields will not restore (all) the values, but merely the ones that exist at the time of the page loading. In some cases, for example cascading dropdowns, will not be shown or exist at all at the time of the page load.

What we will accomplish in this part is to push into the query string (without reloading the page!) the selected make and the selected model (where applicable).

We are going to make use of:

JavaScript
history.replaceState(...)

function. There is a W3C standard available for this function (and others). Note that this is supported on all browsers, but only the recent versions.

To do so, we need a few things:

  • A function to parse (a) query string; sadly JavaScript does not have anything built in, not even jQuery is of much help
  • Change the URL upon changing of selection
  • Restore selection from the URL – including cascading

Great! Let’s start.

Upon a bit of searching around which turned into stackoverflowing, I reached the most voted question on this matter called ‘How can I get query string values in JavaScript?‘.

I really looked for a quick-simple-and-standards-compliant-and-so-on solution but the best I could scavenge was this:

JavaScript
function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

Ugly, but it works.

We already have a bit of initialization (quick tip/reminder : in jQuery, you can write a function that will execute upon document ‘ready’ just like so: $(function() { /* … */ }); ):

JavaScript
$(function () {
    $("#SelectedMake").change(makeChanged);
    makeChanged(); // <- this wasn't really necessary
});

Let’s add an event handler for the change of the selected model in order to change the URL from there, too:

$(function () {
    $("#SelectedMake").change(makeChanged);
    $("#SelectedModel").change(modelChanged);
});

// ...

function modelChanged() {
    var makeId = getParameterByName("mkId", document.location.href);
    var modelId = $("#SelectedModel").val();
    if (!modelId)
        history.replaceState(null, null, "/Home/Selector?mkId=" + makeId);
    else
        history.replaceState(null, null, 
        "/Home/Selector?mkId=" + makeId + "&mdId=" + modelId);
}

We also need to change the makeChanged logic in order to simplify the function and allow future reuse of the Ajax populating call (changed lines are highlighted) :

JavaScript
function loadModels(make, pushState, onSuccess) {
    $.ajax({
        cache: true,
        type: 'GET',
        url: '@Url.Action("GetModelsByMake")',
        data: { 'makeId': make },
        success: function (data) {
            if (pushState)
                history.replaceState(null, null, "/Home/Selector?mkId=" + make);
            var models = $("#SelectedModel");
            models.empty();
            models.append($("<option></option>").attr
            ("value", "").text(" -- please select a model -- "));
            $.each(data, function (key, val) {
                models.append($("<option></option>").attr
                ("value", val.Id).text(val.Text));
            });
            $('#divModel').show();
            if (onSuccess)
                onSuccess();
        },
        error: function (xhr, ajaxOptions, error) {
            alert(error);
            $('#divModel').hide();
        }
    });
}

function makeChanged() {
    var selectedMake = $("#SelectedMake").val();
    if (selectedMake === "") {
        $('#divModel').hide();
    } else {
        loadModels(selectedMake, true);
    }
}

We refactored out the Ajax call into the loadModels function and added two parameters:

  • pushState – This would control whether after successfully loading the models, the URL should be changed or not
  • onSuccess – An option callback to be executed after successfully loading the models

At this point, if we run the sample, we should have URL changing functionality fully implemented but if we submit into the next page and go back to the selector page only the make dropdown will have its selection restored and that isn’t our work but the browser’s (this worked from the beginning).

Finally, in order to restore selection from the URL, a bit of initialization is necessary:

JavaScript
$(function () {
    init();
    $("#SelectedMake").change(makeChanged);
    $("#SelectedModel").change(modelChanged);
});

// ... 

function init() {
    var makeId = getParameterByName("mkId", document.location.href);
    if (!makeId) return;
    var modelId = getParameterByName("mdId", document.location.href);
    loadModels(makeId, false, function () {
        $("#SelectedModel").val(modelId);
    });
}

.. and now all should work smooth! :)

You can check out the code on Github.

This article was originally posted at http://blog.andrei.rinea.ro?p=524

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) IBM, Business Analytics
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --