Search code examples
javascriptjquerybootstrap-tour

Skipping steps in bootstrap tour using conditional if / else checks with goTo()


first time asking a question here so I'm hoping I have all the information but feel free to ask for clarification if I'm missing something.

I'm trying to create a tour through a page using the bootstrap tour library. I can get it to start, and for the most part it runs fairly smoothly except when I'm trying to get it to check for a variable and skip certain steps as required.

I can't copy my entire codebase in my real project, so I tried to make a jsfiddle with the relevant parts that I could figure out. I admit that I've never used jsfiddle before and it's not working I think because I might not have gotten the tour files to load correctly. I have linked to the standalone files so that they contain the relevant bits of bootstrap needed to run. I admit I'm a total jsfiddle newb so I'm not sure why the files don't seem to be loading and firing correctly, but that's a totally different error. Anyway, here's my basic code:

Html:

<body>
<button id="start" class="btn btn-default">Start the tour</button>
<div id="box1" class="box">Element 1</div>
<div id="box2" class="box">Element 2</div>
<div id="box3" class="box">Element 3</div>
<div id="box4" class="box">Element 4</div>
<div id="box5" class="box">Element 5</div>
</body>

js:

var foo = true;

var tour = new Tour({
    storage: false,
    debug: true,
    steps: [
        {
            orphan: true,
            animation: true,
            backdrop: true,
            title: "index 0 / Step 1",
            content: "schtuff"
        }, {
            animation: true,
            element: "#box1",
            placement: right,
            title: "index 1 / Step 2",
            content: "click this box to continue, should skip to Index 5 / Step 6",
            template: "<div class='popover tour'>"+
                            "<div class='arrow'></div>"+
                            "<h3 class='popover-title'></h3>"+
                            "<div class='popover-content'></div>"+
                            "<div class='popover-navigation'>"+
                            "</div>"+
                        "</div>",
            onNext: function(tour){
                if (foo == true){
                    alert("skip to 5");
                    tour.goTo(5);
                } else {
                    tour.next();
                };
            }
        }, {
            orphan: true,
            animation: true,
            backdrop: true,
            title: "index 2 / Step 3",
            content: "moar schtuff"
        }, {
            element: "#box2",
            placement: right,
            title: "Index 3 / Step 4",
            content: "schtuff"
        }, {
            element: "#box3",
            placement: right,
            title: "Index 4 / Step 5",
            content: "schtuff"
        }, {
            element: "#box4",
            placement: right,
            title: "Index 5 / Step 6",
            content: "schtuff"
        }
    ]
});

$("#start").on("click", function(){
    tour.start(true);
};

//initialize the tour
tour.init();

I have read through the questions on here like this one and it's close, but the issue that I'm coming across is that because there is an if/else check in the onNext function, when I'm running the debugger in the console in chrome it will check for the variable to be true, will skip ahead and show the correct tooltip, but will ALSO fire the regular 'next' function even though it can't be seen. I only see it fire in the debugger tool that shows in the console. When 'next' is clicked on the correct further-along tip, instead of continuing along the array through the remaining tips, it acts as if 'next' were hit on the original tool tip. (this is confusing to describe sorry).

So if tour(0) --> tour(1) --> (check if foo = true) --> tour(5) --> (instead of going to tour(6) it's going back and firing tour(3) because it thinks that tour(5) is actually tour(2)

Maybe I'm just fundamentally not understanding how the tour.goTo() function is supposed to work, but I'm just running out of ideas. What I have tried is to stop the tour in the if statement so

if (foo == true){
    tour.end();
    tour.start(true);
    tour.goTo(5);
} else {
    tour.next();
}

This throws errors in the console saying that the showStep cannot be shown because the tour has ended. Strangely, in another part of my page I had to stop the tour and use a timeout to restart (I had to wait for an element to load), and the end-start-goTo worked just fine. That code looks like this (but is not in the jsfiddle):

onNext: function(tour){
    tour.end();
    setTimeout(function(){
        tour.start(true);
        tour.goTo(4);
    }, 500);
}

It appears that it's the if/else statement that seems to be causing the problem, by not choosing between the two options, but rather by firing both.

Thank you in advance for any help that you can give me. And sorry for the novel, but I wanted to make sure that I gave as much information as I could.


Solution

  • After walking through the code, it doesn't appear that you can trigger a different step in the onNext handler. This is because the "next" button is set up at the time that the step is shown with an action to show the next step in sequence (also determined at the time the step is shown). I don't see any way given, either, to prevent the previously set up handler from firing. This happens because they capture the current step in the helper function that shows the next step at the time the current step is shown. The goTo method does not seem to preempt this helper callback either.

    I was, however, able to make it work using a different tactic, namely, don't use a traditional "next" button on the step with the optional path, but instead show it without the role (which the tour uses to attach the handler) and add a handler directly for the button that performs the optional navigation.

    Replace your template with:

    template: "<div class='popover tour'>" +
        "<div class='arrow'></div>" +
        "<h3 class='popover-title'></h3>" +
        "<div class='popover-content'></div>" +
        "<div class='popover-navigation'>" +
        "<button class='btn btn-default' data-role='prev'>« Prev</button>" +
        "<span data-role='separator'>|</span>" +
        "<button id='skipBtn' class='btn btn-default'>Next »</button>" +
        "<button class='btn btn-default' data-role='end'>End tour</button>" +
        "</div>" +
        "</div>",
    

    And add a delegated handler to the document for the skipBtn in the template.

    $(document).on('click', '#skipBtn', function(e) {
        e.preventDefault();
        if (foo) {
            tour.goTo(5);
        }
        else {
            tour.next();
        }
    });
    

    You'll also need to remove the onNext handler.

    Working fiddle at https://jsfiddle.net/vgayf3sL/

    Note: The errors you had with your fiddle where bare right placement values. They needed to be quoted and you were missing a closing parenthesis after the #start click handler. You should be able to view the browser debugger console to see those errors.