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

onSubmit stripped for Forms #128

Closed
winkerVSbecks opened this issue Apr 20, 2016 · 21 comments
Closed

onSubmit stripped for Forms #128

winkerVSbecks opened this issue Apr 20, 2016 · 21 comments

Comments

@winkerVSbecks
Copy link
Contributor

Trying to test a button that allows form submissions:

import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import Button from '../button';

storiesOf('Button', module)
  .add('submit for a form', () => (
    <div className="p4 center">
      <form
        onSubmit={ () => action('form submitted') }>
        <Button type="submit">Submit</Button>
      </form>
    </div>
  ));

It seems that onSubmit gets stripped when it loads in React Storybook. I've tried different combinations: wrapping it with a div, making it the root component, using a custom Form component, etc. In all cases the onSubmit is stripped out. Any idea what I'm doing wrong? Or are forms not supported by React Storybook?

@winkerVSbecks winkerVSbecks changed the title onSubmit stripped for Forms onSubmit stripped for Forms Apr 20, 2016
@akblurton
Copy link
Contributor

akblurton commented Apr 20, 2016

You need to pass in just the call to action() not a function that calls it:

<form onSubmit={action('form submitted')}>

This doesn't prevent the default action on the form though, so the iFrame will reload. Not sure how you could handle this outside storing the created action:

const submitAction = action('form submitted');
storiesOf('Button', module)
  .add('submit for a form', () => (
    <div className="p4 center">
      <form
        onSubmit={ e => { e.preventDefault(); submitAction(e); }}>
        <Button type="submit">Submit</Button>
      </form>
    </div>
  ));

@winkerVSbecks
Copy link
Contributor Author

I see, thanks for explaining that.

ndelangen pushed a commit that referenced this issue Apr 5, 2017
add projectDir as a packager projectRoot
@hmontes
Copy link

hmontes commented Aug 15, 2017

I found a better way.

onSubmit={ e => { e.preventDefault(); action('form submitted')(e); }}>

So. We need a better action with a e.preventDefault integrated.

@Hypnosphi
Copy link
Member

@hmontes You just inlined a variable, why do you think it's better?

@hmontes
Copy link

hmontes commented Aug 16, 2017

@Hypnosphi Because if i have several buttons in a component (example. A modal with a Close button and a send form button) i can use different actions (action('Modal closed'), action('Submitted Form').

@Hypnosphi
Copy link
Member

But you only need preventing default on form submit button

@hmontes
Copy link

hmontes commented Aug 16, 2017

Yes. Because "action" don't have a natural way to do that. (I spend hours to find a way to prevent default an event in storybook)

@Hypnosphi
Copy link
Member

If you have several forms, you may want to create a function like this:

const withPreventDefault = handler => e => {
  e.preventDefault();
  handler(e);
}

And use it like that:

onSubmit={ withPreventDefault(action('form submitted')) }

@hmontes
Copy link

hmontes commented Aug 16, 2017

Yeah. But that function is INSIDE the component.

The solution is for the Story. If you have a presentational component and a container you want to disable the event OUTSIDE of the presentational component (And in this case. In the story) because the presentational components aren't classes.

@Hypnosphi
Copy link
Member

Sorry, but I don't get what you're talking about. Please provide an examle

@plummer-flex
Copy link

It seems I'm late to the party, but this is still a problem.

            <form
              onSubmit={(e) => {
                e.preventDefault();
                action('form submitted')(e);
              }}
            >
              <input type="text" />
              <Button type="submit">Submit Button</Button>
            </form>

We're not relegating the form submission to the onSubmit event on the form node, and not the onClick event on the Button. If the code doesn't use e.preventDefault(), the iframe then forwards off to the root iframe and borks the Storybook frame. It would be better for the action to prevent default.

@Hypnosphi
Copy link
Member

@plummer-flex Feel free to add this to your codebase

import {action} from '@storybook/addon-actions`

export const actionWithPreventDefault = name => e => {
  e.preventDefault();
  action(name)(e);
}

@plummer-flex
Copy link

@Hypnosphi I get the adding another wrapper function so as to not use an inline function, but what's the case for not modifying action to handle this on it's own?

@Hypnosphi
Copy link
Member

Hypnosphi commented May 29, 2020

Because increasing API surface for each possible usecase is impractical

@njcaballero
Copy link

njcaballero commented Dec 11, 2020

import {action} from '@storybook/addon-actions`

export const actionWithPreventDefault = name => e => {
e.preventDefault();
action(name)(e);
}

Now that @storybook/addon-actions is part of the essentials, I'm not able to import action anymore (even though it is installed as a dependency already). I checked the new action page here: https://storybook.js.org/docs/react/essentials/actions and looks like this is now handled differently. I was able to add an event for a button click, but still can't find how to prevent default for an onSubmit event using the new way.

Using Storybook v6.1.5

To clarify, I do see a "submitted" event showing in the action panel, but it immediately redirects to a "No Preview" page.

@shilman
Copy link
Member

shilman commented Dec 13, 2020

@njcaballero all the 6.x changes should be backwards compatible, i.e. action(x)(e) should still work. if you're getting a warning about package dependencies you can just install addon-actions as a dev dependency to your project. it won't affect essentials.

if you want to use the "new way" of doing things where onX is automatically filled in via args, it would look something like this (react example)

const withPreventDefault = (action) => e => {
  e.preventDefault();
  return action(e);
};

const Template = ({ onClick, ...rest }) => (
  <MyComponent onClick={withPreventDefault(onClick)} {...rest} />
)

@njcaballero
Copy link

@shilman That worked for me. Thanks!

@vdpdev

This comment has been minimized.

@Hypnosphi

This comment has been minimized.

@vdpdev

This comment has been minimized.

@Hypnosphi

This comment has been minimized.

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

No branches or pull requests

8 participants