usablica/intro.js · error

Provided callback for onAfterChange was not a function

Error message

Provided callback for onAfterChange was not a function

What it means

Tour class onAfterChange registers the callback run after each step change, stored in this.callbacks.afterChange. It throws this error when the argument is not a function, per the shared validation pattern across intro.js setter methods.

Source

Thrown at src/packages/tour/tour.ts:562

    this.callbacks.change = callback;
    return this;
  }

  /**
   * @deprecated onafterchange is deprecated, please use onAfterChange instead.
   */
  onafterchange(callback: introAfterChangeCallback) {
    this.onAfterChange(callback);
  }

  /**
   * Add a callback to be called after the tour changes steps
   * @param {Function} callback callback function to be called
   */
  onAfterChange(callback: introAfterChangeCallback) {
    if (!isFunction(callback)) {
      throw new Error("Provided callback for onAfterChange was not a function");
    }

    this.callbacks.afterChange = callback;
    return this;
  }

  /**
   * @deprecated oncomplete is deprecated, please use onComplete instead.
   */
  oncomplete(callback: introCompleteCallback) {
    return this.onComplete(callback);
  }

  /**
   * Add a callback to be called when the tour is completed
   * @param {Function} callback callback function to be called
   */
  onComplete(callback: introCompleteCallback) {

View on GitHub (pinned to e5517e6a24)

Solutions

  1. Pass a real function: introJs().onAfterChange(function(targetElement){ ... }).
  2. Fix the undefined source: correct the config key, import, or variable name.
  3. Coalesce with a default: introJs().onAfterChange(cfg.afterChange || (() => {})).
  4. Move registration into initialization code that runs after handlers are defined.
  5. Add a caller-side type guard before invoking the setter.

Example fix

// before
introJs().onAfterChange(config.afterChange); // key is 'afterChangeCb'
// after
introJs().onAfterChange(config.afterChangeCb);
Defensive patterns

Strategy: validation

Validate before calling

const after = cfg.afterChangeCb;
if (typeof after !== 'function') { throw new TypeError('afterChangeCb must be a function'); }
introJs().onAfterChange(after);

Type guard

const isCallable = (v: unknown): v is () => void => typeof v === 'function';

Try / catch

try {
  intro().onAfterChange(cb);
} catch (e) {
  if (e.message.includes('onAfterChange was not a function')) {
    console.error('onAfterChange callback invalid:', cb);
    intro().onAfterChange(() => {});
  } else { throw e; }
}

Prevention

When it happens

Trigger: introJs().onAfterChange() called with undefined/null/non-function — e.g., a typo'd config lookup or a callback name string instead of the function reference.

Common situations: Copy-pasting old intro.js v0.x snippet styles; bundler tree-shaking removing an exported handler referenced by string; optional callbacks in strict config pipelines arriving undefined.

Related errors


AI-assisted analysis of usablica/intro.js@e5517e6a24 (2026-08-31). Data as JSON: /api/errors/94aea3648f99768f. Report an issue: GitHub.