deep code dive

The project’s budget did not have room to develop the fancy ‘card-animated-loading’ behavior noted in the specs (with this example as reference). I settled on isotope, the page needed to show / hide cards based on filters.

Enabling the initial filters and animations worked well.

var iso = new Isotope('#redsblue-items', {
    itemSelector: '.redblue-item'
});

Some lists of the cards had a ‘Load More’ button, where new cards slide up when loaded. I set options to use translateY(200px) when hidden and translateY(0) when made visible.

var iso = new Isotope('#redsblue-items', {
    itemSelector: '.redblue-item',
    hiddenStyle: {
        transform: 'translateY(200px)'
    },
    visibleStyle: {
        transform: 'translateY(0)'
    }
});

The translateY transform was occurring, but items hidden by filtering were not going away (note the blue behind the red below).

Iterations on the options did not produce the desired result or clues on an explanation.

This was the moment we dread when external code is brought to a project, and there’s a choice to make between finding another widget, or diving in to this widget’s code to find out why the new options cause undesired behavior.

There weren’t other widgets that met the criteria as closely, it was worth spending some time on the dive.

Often a less than enjoyable task. Reading and debugging code I didn’t write, or code I wrote more than 2 months days ago. Beyond not being my code, layout changes with transitions and event handling the end of transitions is tough to keep straight.

Four hours and 3000 breakpoints (both numbers approximate) later, I found the cause in the hide function of outlayer’s item.js (isotope uses outlayer).

this.transition({
    from: options.visibleStyle,
    to: options.hiddenStyle,
    // keep hidden stuff hidden
    isCleaning: true,
    onTransitionEnd: {
        opacity: function() {
            // check if still hidden
            // during transition, item may have been un-hidden
            if ( this.isHidden ) {
              this.css({ display: 'none' });
            }
        }
    }
});

The onTransitionEnd object is used to set callback functions to be executed in the ontransitionend event of each filtered element. In that event handler, the onTransitionEnd object is checked for the style property whose transition has just ended, and executes the function provided here. For isotope to hide an item after filtering it, opacity needs to transition.

opacity is one of the styles used to show/hide items in the default options, adding it to the hiddenStyle option override restores expected behavior for the filtered cards.

var iso = new Isotope('#redsblue-items', {
    itemSelector: '.redblue-item',
    hiddenStyle: {
        opacity: 0,
        transform: 'translateY(200px)'
    },
    visibleStyle: {
        opacity: 1,
        transform: 'translateY(0)'
    }
});

Or with this fix, the filtered items will be hidden after their transition without specifying the opacity in hiddenStyle.

var iso = new Isotope('#redsblue-items', {
    itemSelector: '.redblue-item',
    hiddenStyle: {
        transform: 'translateY(200px)'
    },
    visibleStyle: {
        transform: 'translateY(0)'
    }
});

Final example here.

posted: 12/01/2014