Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@storybook/html - can't run JS in story #7786

Closed
whoisryosuke opened this issue Aug 17, 2019 · 13 comments
Closed

@storybook/html - can't run JS in story #7786

whoisryosuke opened this issue Aug 17, 2019 · 13 comments

Comments

@whoisryosuke
Copy link
Contributor

whoisryosuke commented Aug 17, 2019

Describe the bug

Can't run JS functions alongside HTML of story.
I need to run a jQuery function once the page loads, and none of the methods (using Event Listeners and DOMContentLoaded) I've discovered seem to work.

To Reproduce

  1. Create a story with the JS before the story is returned:
import { storiesOf } from "@storybook/html";

import "../../../dist/semantic.min.css";
import "../../../dist/semantic.min.js";

import Frontpage from "./Frontpage.html";

storiesOf("Page: Frontpage", module).add("Standard", () => {
  function init() {
    $(".ui.dropdown").dropdown({
      on: "hover"
    });
    console.log("ran function");
  }
  document.addEventListener("DOMContentLoaded", init);
  return Frontpage;
});

or more complex example using a Mutation Observer:

storiesOf("Page: Frontpage", module).add("Standard", () => {
  function pageScript() {
    console.log("Page has changed!");
  }
  document.addEventListener(
    "DOMContentLoaded",
    function() {
      pageScript();
      const callback = function(mutationsList) {
        for (let i = 0, len = mutationsList.length; i < len; i++) {
          if (mutationsList[i].type == "childList") {
            pageScript();
            break;
          }
        }
      };

      const observer = new MutationObserver(callback);
      const config = {
        childList: true,
        subtree: false
      };
      observer.observe(document.getElementById("root"), config);
    },
    false
  );
  return Frontpage;
});

Expected behavior
Runs JS on story load and when content changes.

Code snippets
see above

System:

Environment Info:

System:
OS: macOS 10.14
CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
Binaries:
Node: 8.12.0 - /usr/local/bin/node
npm: 6.4.1 - /usr/local/bin/npm
Browsers:
Chrome: 76.0.3809.100
Firefox: 61.0.2
Safari: 12.0
npmPackages:
@storybook/addon-a11y: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-actions: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-backgrounds: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-centered: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-events: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-jest: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-knobs: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-links: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-notes: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-options: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-storyshots: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-storysource: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addon-viewport: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/addons: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/core: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/core-events: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/html: 5.2.0-alpha.35 => 5.2.0-alpha.35
@storybook/source-loader: 5.2.0-alpha.35 => 5.2.0-alpha.35

Additional context

  • Using Semantic UI and jQuery.
  • SUI is local, jQuery is NPM module that's globally registered in storybook.config.js.
@shilman
Copy link
Member

shilman commented Aug 17, 2019

@whoisryosuke Super hacky and I'm sure there's a better solution, but have you tried a setTimeout just to see if it works?

@ndelangen we have APIs for registering for channel events. Are they accessible when I'm writing a story?

@Hypnosphi Hypnosphi self-assigned this Aug 17, 2019
@Hypnosphi
Copy link
Member

Hypnosphi commented Aug 17, 2019

This probably means that DOMContentLoaded is already fired at the moment when story function is called. In 5.2.0-beta, you can try using Storybook hooks instead:

import { storiesOf } from "@storybook/html";
import { useEffect } from "@storybook/client-api";

import "../../../dist/semantic.min.css";
import "../../../dist/semantic.min.js";

import Frontpage from "./Frontpage.html";

storiesOf("Page: Frontpage", module).add("Standard", () => {
  useEffect(() => {
    $(".ui.dropdown").dropdown({
      on: "hover"
    });
    console.log("ran function");
  }, []);
  return Frontpage;
});

@shilman
Copy link
Member

shilman commented Aug 17, 2019

@Hypnosphi this is really awesome ❤️

@Hypnosphi
Copy link
Member

@shilman unfortunately, it doesn't work yet: the effects are triggered too early. I'll send a PR shortly

@shilman
Copy link
Member

shilman commented Aug 19, 2019

Yowza!! I just released https://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.36 containing PR #7791 that references this issue. Upgrade today to try it out!

You can find this prerelease on the @next NPM tag.

Closing this issue. Please re-open if you think there's still more to do.

@shilman shilman closed this as completed Aug 19, 2019
@lkraav
Copy link

lkraav commented Oct 28, 2019

This probably means that DOMContentLoaded is already fired at the moment when story function is called. In 5.2.0-beta, you can try using Storybook hooks instead:

Hi @Hypnosphi @ndelangen what's today's state of documentation for Storybook hooks? I see https://storybook.js.org/docs/addons/api/#storybook-hooks exists, but useEffect as shown at #7786 (comment) is nowhere to be seen?

Algolia search on website finds no matches for "useEffect".

I tested it, and it seems to work exactly as needed. How come the docs missing on it?

@Hypnosphi
Copy link
Member

Unfortunately, the docs only exist in form of inline comments: https://github.com/storybookjs/storybook/blob/next/lib/addons/src/hooks.ts#L279

@ndelangen
Copy link
Member

@lkraav a PR on the docs would be super super useful, maybe you'd be able to contribute?

@lkraav
Copy link

lkraav commented Nov 16, 2019

In a 1 month time horizon yes. Within the next 2 weeks, probably not. Main barrier is learning what the current practices and setup for docs here is, and figuring out what exactly to write. Brainspace is extremely limited due to an ongoing project.

@mhorne89
Copy link

I worked around this simply by using jQuery's document ready function.

$(document).ready(function() {
    ...
});

@tklives
Copy link

tklives commented Feb 2, 2022

Any chance someone could provide an example of how the useEffect() would work using MDX?

Even with having all of my logic for my demo in a separate .tsx file that I import into the .stories.mdx file, it seems as if the code is still executing before storybook is ready and so it throws errors. I'm ultimately looking into using a MutationObserver as well and am currently only able to get things working with a setTimeout, but would much prefer a cleaner way of doing this. Thanks in advance!! :)

@hungcung2409
Copy link

hungcung2409 commented Jul 7, 2023

Now I'm just using setTimeout. Hope we can have a better solution
In my case, I pass this bellow to render function:

{
    ...otherStuffs,
   render: () => {
     // Create DOM element
     const ele = document.createElement('div');

     setTimeout(() => {
        // Do anything to your element's been created before
     })
     return ele.innerHTML;
   }
}

@ndelangen
Copy link
Member

I think y'all might be interested to learn about the storybook play function:
https://storybook.js.org/docs/react/writing-stories/play-function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants