2

I am using Bootstrap Tour and it is very simple to setup.

These are the instructions:

// Instance the tour
var tour = new Tour({
  steps: [
  {
    element: "#my-element",
    title: "Title of my step",
    content: "Content of my step"
  },
  {
    element: "#my-other-element",
    title: "Title of my step",
    content: "Content of my step"
  }
]});

// Initialize the tour
tour.init();

// Start the tour
tour.start();

In my case, I have a Profiles#Index, Profiles#Show and Dashboard#Index -- all of which have different elements that I want to give the tour on. So I need to specify different elements for all actions/views which are different.

I also only want to trigger the tour under the following conditions:

  • The first time the user logs on (can be determined by current_user.sign_in_count < 2).
  • Only when the user first logs in, and not when they refresh the page.

I am using Devise, FYI.

I am now putting the default JS in my app/assets/javascripts/profiles.js. Should I move it elsewhere to be able to achieve my above conditions?

Edit 1

Actually, I thought it would work normally but I can't even get it to work at all.

I am on my Profiles#Show page and the tour doesn't trigger. This is how it is setup:

This is my application.html.erb:

<%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/css/bootstrap-tour.min.css", 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/js/bootstrap-tour.min.js", 'application', 'data-turbolinks-track': 'reload' %>

This is my application.js:

$(document).on('turbolinks:load', function() {
  var tour = new Tour({
    backdrop: true,
    steps: [
    {
      element: "#ratings-controls",
      title: "Ratings Controls",
      content: "Here you can rate this recruit so you can easily remember how they performed."
    },
    {
      element: "div.action-buttons a#favorite-btn",
      title: "Favorite",
      content: "Here you can easily favorite a player"
    },
    {
      element: "a.my-favorites",
      title: "My Favorites",
      content: "After you favorite a player, they automagically get added to your list of favorites -- which you can easily view here."
    }
  ]});

  // Initialize the tour
  tour.init();

  // Start the tour
  tour.start();
});

I initially had this in my app/assets/javascripts/profiles.js but when it stopped working, I moved it to application.js just to make sure something else wasn't overriding it.

In my Profiles#Show, I have all of those 3 elements for sure, as you can see in the rendered HTML below:

<div id="ratings-controls" class="profile-data">
  <table class="table table-condensed">
      <tbody>
      <tr>
          <td>
              <p>
                <button type="button" class="btn btn-success m-r-sm slider-step-value" id="slider-step-value-speed-wacky-dip-st-george-s-college-bcdda202-c498-4baa-867d-200662fc785b" data-speed-value="0">0</button>
                Speed
              </p>
              <div id="slider-speed" class="slider"></div>
          </td>
          <td>
              <p>
                <button type="button" class="btn btn-info m-r-sm slider-step-value" id="slider-step-value-tackling-wacky-dip-st-george-s-college-bcdda202-c498-4baa-867d-200662fc785b" data-tackling-value="0">0</button>
                Tackling
              </p>
              <div id="slider-tackling" class="slider"></div>
          </td>
      </tr>
      <tr>
          <td>
              <p>
                <button type="button" class="btn btn-primary m-r-sm slider-step-value" id="slider-step-value-dribbling-wacky-dip-st-george-s-college-bcdda202-c498-4baa-867d-200662fc785b" data-dribbling-value="0">0</button>
                Dribbling
              </p>
              <div id="slider-dribbling" class="slider"></div>
          </td>
          <td>
              <p>
                <button type="button" class="btn btn-warning m-r-sm slider-step-value" id="slider-step-value-passing-wacky-dip-st-george-s-college-bcdda202-c498-4baa-867d-200662fc785b" data-passing-value="0">0</button>
                Passing
              </p>
              <div id="slider-passing" class="slider"></div>
          </td>
      </tr>
      </tbody>
  </table>
</div>

<div class="action-buttons">
  <a class="btn btn-xs btn-success" id="favorite-btn-29" data-remote="true" rel="nofollow" data-method="post" href="/profiles/wacky-dip-st-george-s-college-bcdda202-c498-4baa-867d-200662fc785b/favorite"><i class='fa fa-thumbs-up'></i> Favorite</a>
</div>

<a class="my-favorites" href="/profiles?filter=favorites">
  <i class="fa fa-list"></i> My Favorites
</a>

Also, the Bootstrap Tour CSS & JS are being included in my rendered HTML.

So the first question is...how do I even get this working? Then I can get to the others.

Edit 2

I added some debugging statements to my application.js and these are the results.

This is how my application.js looks now:

$(document).on('turbolinks:load', function() {
  console.log('Turblinks Has Loaded -- This is Before Tour is Initialized.')
  var tour = new Tour({
    backdrop: true,
    steps: [
    {
      element: "#ratings-controls",
      title: "Ratings Controls",
      content: "Here you can rate this recruit so you can easily remember how they performed."
    },
    {
      element: "div.action-buttons a#favorite-btn",
      title: "Favorite",
      content: "Here you can easily favorite a player"
    },
    {
      element: "a.my-favorites",
      title: "My Favorites",
      content: "After you favorite a player, they automagically get added to your list of favorites -- which you can easily view here."
    }
  ]});

  // Initialize the tour
  tour.init();
  console.log('This is after Tour has been initialized.')

  // Start the tour
  tour.start();
  console.log('This is after Tour has been started.')
});


Turblinks Has Loaded -- This is Before Tour is Initialized.
bootstrap-tour.min.js:22 Uncaught TypeError: Cannot read property 'extend' of undefined(…)

What could be causing this and how do I further debug it? The error seems to be within the bootstrap-tour.min.js file.

marcamillion
  • 32,933
  • 55
  • 189
  • 380
  • What's your issue? I see you already have all or most your code. What have you tried or were are you stuck? – MMachinegun Nov 24 '16 at 10:44
  • @marczking My issue is that it doesn't work at all. I have all of the code, but the Tour doesn't execute when the page has finished loading like you would expect. What am I missing? Or what can I try? I see no errors in the JS console. – marcamillion Nov 24 '16 at 17:37
  • Can you make a fiddle or codepen with the basic structure? My guess is that this is not a direct rails issue. Of course you need to populate the views correctly, but I think you should be able to trim it down to the basics just with HTML and JavaScript. I'll try to have a look later today as well. But if you have a Pen or so feel free to link it ;) – MMachinegun Nov 24 '16 at 17:42
  • what is turbolinks and does it have a load event? Maybe you can try to start tour when the document loaded? – Gokhan Demirhan Nov 25 '16 at 12:26
  • 1
    One way I can see this breaking is if you use the [jquery-turbolinks](https://github.com/kossnocorp/jquery.turbolinks) gem. Did you `console.log('something')` in the `turbolinks:load` block to make sure it's behaving as expected? – BigRon Nov 25 '16 at 13:07
  • @Gokhan You can check out Turbolinks here: https://github.com/turbolinks/turbolinks It does have a load event, and I used it in the first line of the JS. – marcamillion Nov 27 '16 at 07:33
  • @BigRon Good suggestion. I added some `console.log(...)` debug statements and I got an error. See the updated question to see where we are now. Thoughts on those errors? – marcamillion Nov 27 '16 at 07:34
  • OK, so we know from the placement of your console.logs that the error occurs inside your line: `tour.init();`, now we can go there to find where the error code occurs (i.e. look for `extend`). Alternatively, in chrome inspector (and I'm sure firebug if you use that) they give you a link to the code where the error occurs. – BigRon Nov 29 '16 at 19:12
  • Did you load your dependencies in the correct order shown [here](http://bootstraptour.com/). Here's why I think that's the problem... I would recommend getting rid of the minified code for now (`bootstrap-tour.min.js`) and replace it with `bootstrap-tour.js`, which you can download [here](https://github.com/sorich87/bootstrap-tour/blob/master/build/js/bootstrap-tour.js). After that re-run the page and check the error. I think you'll see that it occurs on line 43, which looks to me like jquery is not loaded when bootstrap-tour.js is running... – BigRon Nov 29 '16 at 19:30
  • What's with these lines: `<%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/css/bootstrap-tour.min.css", 'application', media: 'all', 'data-turbolinks-track': 'reload' %>` `<%= javascript_include_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/js/bootstrap-tour.min.js", 'application', 'data-turbolinks-track': 'reload' %>` I think they should both say `'data-turbolinks-track': true` rather than `reload` – BigRon Nov 29 '16 at 19:37
  • @BigRon `reload` is to allow it to keep track of changes in cached assets - https://github.com/turbolinks/turbolinks#reloading-when-assets-change – marcamillion Nov 30 '16 at 09:24
  • @marcamillion cool note about `reload` I'll have to see if I can use that – BigRon Nov 30 '16 at 15:51

2 Answers2

1

New Answer

After reading the Bootstrap Tour docs it sounds like your issue could be the way Bootstrap tour saves a cookie in your local storage to keep track of the user's progress on the tour. In other words the reason the tour won't start is because Bootstrap tour looks in your browsers local storage and thinks you are already done. So to fix this you have three options, depending on your exact circumstances:

  1. Force Bootstrap tour to NOT use storage

    // Instance the tour
    var tour = new Tour({
      storage: false,
      steps: [ ...]
    ]});
    

or

  1. Force the tour to start

    // Start the tour
    tour.start(true);
    

or

  1. Force the tour to restart

    // Restart the tour
    tour.restart();
    

Original Answer

I'm making some assumptions based on the comments I provided above and some debugging, and it looks like your javascript files are not included in the correct sequence or manner. This is further complicated by the recent Rails 5 changes to turbolinks. In the rapid prototyping world of rails this is when I turn to a lightweight gem for asset inclusion. In your case I would recommend:

getting rid of:

application.html.erb

<%= stylesheet_link_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/css/bootstrap-tour.min.css", 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/js/bootstrap-tour.min.js", 'application', 'data-turbolinks-track': 'reload' %>

and installing the bootstrap-tour-rails gem like so:

Gemfile

gem 'bootstrap-tour-rails'

application.js

//= require bootstrap-tour

application.css

*= require bootstrap-tour

BigRon
  • 3,182
  • 3
  • 22
  • 47
  • 1
    I tried this, but the issue is the `application.css` requirement. I only have `application.scss`, and the gem didn't have `sass` support. – marcamillion Nov 30 '16 at 08:54
  • So I tried your solution of making sure my dependencies are being loaded in the right order and that fixed that problem. However, the tour is not starting. So the page loads, and I see all of my `console.log` messages....but I am not seeing the tour actually start. – marcamillion Nov 30 '16 at 09:22
  • @marcamillion in regards to the gem here's a solution: if you have any sass in your `application.scss` move it out of that file and into a file called `custom.css.scss` in your `assets/stylesheets` folder (the styles in `custom.css.scss` will be available in every view as long as you have `*= require tree .` in `application.scss`), rename `application.scss` to `application.css` (now that you don't have any sass in there). – BigRon Nov 30 '16 at 15:46
  • @marcamillion in regards to the dependency order... All the `console.logs` run, the tour doesnt start, AND there are NO errors? ... that sounds like something wrong with your code in `var tour = ...`. I'll look through the docs a bit to see if I can spot it – BigRon Nov 30 '16 at 15:47
  • did you try passing `true` into your start block: `tour.start(true);` – BigRon Nov 30 '16 at 16:01
  • 1
    So it seems you were correct. The issue seems to be related to the storage. Your fix of specifying `storage: false`, fixes it perfectly for me. I didn't need to specify `tour.start(true)`. Thanks much. – marcamillion Nov 30 '16 at 17:08
  • that's what I found in my answer as well, just didn't have much time to spend on providing a full answer with code example... – MMachinegun Nov 30 '16 at 17:33
  • @BigRon did you notice this based on my answer or did you find this out yourself? Just curious :P – MMachinegun Nov 30 '16 at 17:35
  • @marczking I ended up figuring it out independently because I was digging through the docs trying to figure out where the `var tour = ...` was incorrect. After reading about `tour.start(true)` I realized you could also set storage to false, but sorry your answer really had found the cause as well – BigRon Nov 30 '16 at 20:58
  • hehe, okay! well deserved bounty in that case :P I was thinking about the issue for a while and finally spent some time on it. Nice find! – MMachinegun Dec 01 '16 at 00:17
1

So I am not seeing you including bootstrap.js, so you might be missing that. Include it before you use bootstrap-tour.js, as that is dependent on bootstrap.js. Check out the overview and docs.

I did a very basic pen and always got this issue: $element.popover not defined. After including bootstrap.js the tour initialises nicely (not styled, but working). Here's my unstyled, but working pen (based on your provided code).

Edit

So it was working on my pen. But once you click "End tour" and reload the page, the tour won't restart. So it is setting a cookie and therefor not restarting the tour. Delete the cookie and the tour will fire off once again.

So I think this might have been your issue all along. The tour should be working fine, but it won't restart once you've ended the tour.

This is you haven't been able to put your head around to what is wrong, as everything looks right, even your code itself!

MMachinegun
  • 3,044
  • 2
  • 27
  • 44
  • Yep, I have Bootstrap included. I am using it in the rest of the project. You were right on the cause of the problem, but the fix was vague. As a result of this, I upvoted you....but can't accept it as the answer because it doesn't tell me specifically what the fix is. Thanks for helping this get resolved though! – marcamillion Nov 30 '16 at 17:10
  • Thanks, glad it helped you somewhat. :) – MMachinegun Nov 30 '16 at 17:32