Search code examples
javascriptjqueryajaxhashchange

Implementing location.hash bound bidirectionally to AJAX record-context


I have a simple javascript AJAX application that allows search and selection of records. Selection updates the location.hash and loads the associated record detail, and ideally vice-versa also (loading a record when the hash changes). Of course a careless implementation can cause loops and extra panel flashes.

I want a predictable and concise implementation of this bidirectional binding.

One approach is to only load a record on the hashchange event, and when a record is selected in the UI, set location.hash. This seems most concise, but I'd be concerned this would diminish record-click responsiveness in older browsers with a polled hashchange shim.

Another approach is to record a navigating (e.g.) state when selecting a record, and clear it when handling hashchange. That's covered in this question. However, that seems like certain event sequences, like tapping Back multiple times rapidly, might result in inconsistency between the displayed content and URL.

Have you seen an implementation that solves these problems?


Solution

  • I think there's a simple answer in my case, since it's a read-only/idempotent operation (well, it actually logs a view).

    I'll just store the state displayed by the current content, and test it on each event that would load content (including the 'redundant' hashchange events), ignoring the event if it matches the currently-displayed state.

    Seems cheap, for better or worse. :)

    here's my approximate/pseudo-code:

    var activeRecordId;
    function loadHash() {
        var idList = window.location.hash.substring(1).split(',');
        if (idList.length > 1) loadSpecificRecordsToList(idList);
        else if (idList != '') loadDetailRecord(idList[0]);
    }
    function loadDetailRecord(id) {
        if (id != activeRecordId) {
            activeRecordId = id;
            doDetailLoadAjaxAndSuch(id);
        }
    }
    $(function () {
        loadHash();
        $.bind('hashchange', loadHash);
    });