LinkedInAttic / hopscotch

A framework to make it easy for developers to add product tours to their pages.
Apache License 2.0
4.19k stars 664 forks source link

Hopscotch throwing an error on an element that exists on the page #353

Closed troynguyen-dmsi closed 6 years ago

troynguyen-dmsi commented 6 years ago

I am trying to start a tour on a page that has elements load in dynamically. I am waiting until the element my first tour item is pointing at is loaded onto the page until starting the tour. Despite this, hopscotch throws an error on this element (and the element directly after it which is loaded at the same time).

$(function() {
  const tour = {
    id: 'some-tour',
    steps: [
      {
        content: '...',
        target: document.querySelector('.k-nav-prev'),
        placement: '...'
      },
      {
        content: '...',
        target: document.querySelector('.k-i-calendar'),
        placement: '...'
      },
      {
        content: '...',
        target: 'scheduler',
        placement: '...'
      }
    ]
  }

  // poll for first tour element's existence
  // when the element is found to be visible, start tour
  const intervalId = setInterval(function () {
    if ($('.k-nav-prev').is(':visible')) {
      hopscotch.startTour(tour, 0);    
      clearInterval(intervalId);
    }
  }, 250);
});

When I run the above snippet, the first two tour items throw an error, causing the tour to skip the first two items and thus make the third item the tour's starting point. However, if I start the tour manually through the console after the page has loaded, it works exactly as expected, with Hopscotch not skipping any of the elements.

To make sure that the elements truly existed when I start the tour, I declared the following onError callback before I poll for the element's existence:

// on error, change the css of the targets of the first two tour items to red
// both items are loaded from the same call
tour.onError = function() {
  $('.k-nav-prev').css('background-color', 'red');
  $('k-i-calendar').css('background-color', 'red);
}

After adding this onError callback, I receive the same behavior, where an error is thrown on the first two tour items. However, the css of these two items are indeed changed within the onError callback, confirming that the elements exist at the time the Hopscotch error is thrown.

Why is Hopscotch failing to acknowledge the existence of these elements when the same elements can have their CSS changed in the onError callback?

travstone commented 6 years ago

I think you only need the selector (i.e. '.k-nav-prev'), and not the 'document.querySelector' business. See https://github.com/linkedin/hopscotch/issues/105

troynguyen-dmsi commented 6 years ago

Thanks! I changed it to the full element name found by right clicking and pressing "inspect element" and it worked. In my case, I changed my targets to 'li.k-state-default.k-header.k-nav-prev' and 'span.k-icon.k-i-calendar'

troynguyen-dmsi commented 6 years ago

I'm happy it worked, but do you know what the difference is between the two? I'd assume that Hopscotch internally uses document.querySelector

travstone commented 6 years ago

I don't know the internals, but I'm guessing that the target property only gets evaluated when the IIFE executes; if it's a string selector, then hopscotch can look for that element when the tour is run, but if it's a DOM method it would expect an actual element to be the value (which it isn't because the element didn't exist when the method was executed). I'm just guessing tho...