1

I have a function which fades out a div, loads replacement HTML in, and then fades the div back in. This function is being called (correctly) when I click on the navigation bar at the top to load content into #main div. It is also called on the "about" page to load different team profiles in.

The bug occurs when changing off the default team profile. When clicking to view another profile, the function repeats every "#main" change that has happened before clicking on the profile.

The website is https://symbiohsis.github.io/. The visible bug can be reproduced by clicking "About", then clicking on another profile, e.g "B". The profile flashes but is not selected. Selecting profiles after the first on works fine.

The fade in/out & load function:

/* ajax load into $(sel) from newView (e.g. about.html) */
function loadView(sel, newView, checkOrCb, cb) {
    // one of these events will be called when animations end
    var animationEnd = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
    // cache element to change
    var elem = $(sel);

    // if there is a check and callback, do the check
    if (cb) {
        // if the check fails, exit
        if (!checkOrCb(elem, newView))
            return 1;
    }

    // animate out
    elem.addClass("animated fadeOut");
    // when finished load new page and animate in
    elem.one(animationEnd, function() {
        // remove fadeOut animation (while keeping elem hidden)
        elem.css("opacity", 0).removeClass("fadeOut");
        // load new page, then fadeIn
        elem.load(newView, function(text, response, ev) {
            elem.addClass("fadeIn");
            // remove opacity style and animations
            elem.one(animationEnd, function() {
                elem.css("opacity", "").removeClass("animated fadeIn");
            });
            // do the callback if one exists
            if (cb) {
                cb(elem, newView, text, response, ev);
            }
            else if (checkOrCb) {
                checkOrCb(elem, newView, text, response, ev);
            }
        });
    });
}

The navigation bar listeners:

$(".nav_entry").on("click", function() {
    loadView("#main",
        `${$(this).attr("data-link")}.html`,
        function(dummy, newPage) {
            return getCurrentPage() != newPage.replace(".html", "");
        },
        function(dummy, newPage) {
            window.location.hash = newPage.replace(".html", "");
        });
});

The about listeners:

$(".about_icon").on("click", function() {
    var target = $(this);
    loadView("#about_info", `about/${this.innerText.toLowerCase()}.md`, function() {
        return !target.hasClass("about_selected");
    }, function() {
        $(".about_selected").removeClass("about_selected");
        target.addClass("about_selected");
    });
});
// set 2900 team profile as default
$("#about_info").load("about/2900.md");
$(".about_icon:contains(2900)").addClass("about_selected");

How can I fix the bug please? If anyone has any tips on JavaScript conventions that I've missed feel free to add them to your answer/comment :)

DarkMatterMatt
  • 576
  • 10
  • 22
  • What are you doing with `checkOrCb` ? – Robin Mackenzie Jul 10 '17 at 04:52
  • 1
    Hi @DarkMatterMatt. It would really help if you could create a "toy" or isolated example in [jsfiddle](http://jsfiddle.net), codepen, or something similar. 1) it's often hard for someone not familiar with an entire website to follow what the problem is because there are a lot of distractions, 2) A website under development is going to be changing, and 3) We can't edit code, test things, and print diagnostics. That being said, you might want to look into `preventDefault` and `stopPropagation` as these stop the default cascade that occurs after an event fires. – abalter Jul 10 '17 at 04:57
  • https://stackoverflow.com/questions/5963669/whats-the-difference-between-event-stoppropagation-and-event-preventdefault – abalter Jul 10 '17 at 04:58
  • @RobinMackenzie `checkOrCb` is an optional function which is a check (only continue if check == true) if `loadView` is called with four parameters, and is a callback if `loadView` is called with three parameters. @abalter thanks, I'll look into those, and I'll try get a codepen up soonish when I have time – DarkMatterMatt Jul 10 '17 at 05:04

1 Answers1

1

This StackOverflow post was what answered my question / fixed the bug.

Q: The transition ends ... but it works 2 times in Google Chrome.

A: This is because Chrome will fire on both thewebkitTransitionEnd and transitionend events.

I use Visual Event to see what (and how many) event listeners were attached to each object. That showed me that there was a lot of end-transition listeners hanging around on #main. I Googled "jquery one not working" and the first result was the answer which is quoted above.

The solution is to have your own alreadyFired variable to make sure it only fires once.

var animationEndFired = false;
elem.addClass("fadeIn");
// remove opacity style and animations
elem.one(animationEnd, function() {
    // if only fire once
    if (animationEndFired)
        return;
    animationEndFired = true;
Community
  • 1
  • 1
DarkMatterMatt
  • 576
  • 10
  • 22