intro.js icon indicating copy to clipboard operation
intro.js copied to clipboard

On a multipage intro, onexit and oncomplete both trigger between pages [SOLVED with undocumented onskip callback]

Open juliettebeaudet opened this issue 4 years ago • 8 comments

Description

[EDIT - SOLVED - For other introjs users with the same problems, see my solution on codesandbox]
I need some way to guarantee that my code only triggers oncomplete to go from one page to another. Suggestions on how to help:

  • it would be useful that introJs releases an example of multipage with also onexit present in the code, see how you guys solve this conflict;
  • suggest how intermediary "done" buttons (not the final page "done" button one, but all the renamed "next page" done buttons in-between pages), could bear any condition to stop onexit from triggering on it.

Details: I am currently handling a multipage intro. To do so, I use the oncomplete callback, as recommended in the official multipage introjs example, that redirects to the next page url. But I also use the onexit function in case the user wants to skip the whole introduction to our product, redirecting to the home page.

Expected Behavior

Clicking "next page" on the last step of the first page flow, I expect oncomplete to trigger and go to the next page so that the intro flow continues there.

Actual Behavior

Both onexit and oncomplete trigger.

Which makes sense: onexit triggers on the "skip" buttons and also the "done" button, which is the last button of the current page flow (it would be better if it was considered a "next" button in a multipage case...), whereas oncomplete triggers on the completion of the (page) flow, also, then, the "done" button.

However I code it, oncomplete always triggers first. Then, whether the user is redirected to home page (as asked in onexit) or next intro page (as coded in oncomplete) is totally random.

Errors and Screenshots (optional)

I tried to guarantee that oncomplete would be the last one to trigger with setTimeOut or chaining the functions in different orders, with no satisfactory result. Could not find how to get a promise (.then) out of these functions neither.

Example (recommended)

Here is my (simplified) code:

introJs
    .setOptions({
          prevLabel: t('onBoarding.btns.previous'),
          nextLabel: t('onBoarding.btns.next'),
          doneLabel: 'Next page',
          skipLabel: t('onBoarding.btns.skip'),
          exitOnOverlayClick: false,
          scrollToElement: true,
          keyboardNavigation: false,
          tooltipClass: 'customTooltip',
          steps: [
            {
              element: document.querySelector('#collection'),
              intro: t('onBoarding.userProfile.dataStep-1'),
            },
            {
              element: document.querySelector('#about'),
              intro: t('onBoarding.userProfile.dataStep-2'),
            },
            {
              element: document.querySelectorAll('#explore')[0],
              intro: `${t('onBoarding.userProfile.dataStep-4a')}</br></br>${t('onBoarding.userProfile.dataStep-4b')}`,
              position: 'right',
            },
          ],
        })
        .onbeforeexit(function () {
          return confirm('Are you sure you want to leave this onboarding forever & be redirected to home page?');
        })
        .onexit(function () {
          alert('onexit triggered');
          router.push('/');
        })
        .oncomplete(function () {
          alert('oncomplete triggered');
          router.push('/search/projects');
        })
        .start();

You can actually also consult it in its complete (currently overcommented) way, in our open source code .

Environment (optional)

React, Nextjs. Did not use introJs' react wrapper.

juliettebeaudet avatar May 18 '21 21:05 juliettebeaudet

Thanks @juliettebeaudet. I think we can add a config to Intro.js (e.g. multipage_tour?) to change that behavior.

afshinm avatar May 19 '21 07:05 afshinm

Thanks @juliettebeaudet. I think we can add a config to Intro.js (e.g. multipage_tour?) to change that behavior.

Hello @afshinm , thank you, that would be brilliant! 2 more quick questions:

  • Do you have any idea on when you would be able to add this config?
  • In the meantime, could you suggest any solution that would work in the code (like adding some special addeventlistener on the first page done button to tell it to trigger only oncomplete...? I had many ideas but never found how to implement them). Thanks a lot!

juliettebeaudet avatar May 19 '21 11:05 juliettebeaudet

@juliettebeaudet you can simply add a global config (e.g. window.multipage = true) and check it in the oncomplete callback. If that flag is set/or is true, simply ignore the event.

afshinm avatar May 21 '21 07:05 afshinm

@juliettebeaudet you can simply add a global config (e.g. window.multipage = true) and check it in the oncomplete callback. If that flag is set/or is true, simply ignore the event.

@afshinm Thank you. Actually it is the onexit that needs this condition. The difficulty is that onexit triggers both on skip button (to definitely exit, I want to keep that) and on done button (the one I want to lead to next page).

I found the solution: using the onskip callback, available in your lib but surprisingly undocumented, I am able to finally code a difference between the two onexit cases. I also preferred to use localStorage over window.

Here is a codesandbox React code example for complex multipage introductions.

I also committed a suggestion to add the onskip callback on the official documentation, branch jb/docs/onskip (no permission to push it) @afshinm .

juliettebeaudet avatar May 24 '21 20:05 juliettebeaudet

Hello @juliettebeaudet, I have the same problem. But I don't find your solution on code sandbox. Could you explain me or send me the code under onskip function, please. Thanks

jgrojas avatar Oct 21 '22 15:10 jgrojas

Hello @juliettebeaudet, I have the same problem. But I don't find your solution on code sandbox. Could you explain me or send me the code under onskip function, please. Thanks

Hi @jgrojas , sorry to see that my sandbox seems not to have persisted. Basically, from what I remember, the onskip callback helped me to finally detect the difference between the intermediary next buttons and the real final one, and that way, to condition what would happen on each "type" of onexit.

(The code I made at that time was open source, but I just checked and noticed it was totally refactored and the feature was deleted, so I have no way to send you the code I produced at that time.)

Good luck!

juliettebeaudet avatar Oct 21 '22 16:10 juliettebeaudet

@juliettebeaudet thanks for your help, I will try to find the solution with your comment. In any case, your solution to this issue helps me to find a way.

jgrojas avatar Oct 21 '22 17:10 jgrojas