How to include a function in angular storybook args?
Asked Answered
A

2

6

I have a component that has event emitters, and I need to provide a function to it for the component to function correctly.

Used as so:

<my-component (onClick)="myFunction()"></my-component>

So I'm trying this in Storybook, but I can't figure out how to define myFunction() in storybook.

Even when I create myFunction as an arg, I get

ERROR TypeError: ctx.myFunction is not a function
    at StorybookWrapperComponent_Template_my_component_onClick_0_listener (template.html)

So how do I properly define this function. I don't see anything in Storybook's docs mentioning it, but I can't be the only person that needs this...

Relevant Story Code:

export default {
  title: 'My Great Component',
  component: MyComponent
} as Meta<MyComponent>;


const Template: Story<any> = (args) => ({
  props: args,
  template: `<my-component (onClick)="myFunction()"></my-component>`
});


export const Primary = Template.bind({});
Primary.args = {
  myFunction: () => { alert('clicked'); }
}

I've also tried this, thinking that maybe hard coding my function as part of this, it would work, but nope...

export const Primary = Template.bind({myFunction: () => { alert('clicked');});

I'm thinking I might need a wrapper component, but doing that just to make storybook work feels excessive.

Acanthaceous answered 17/3, 2022 at 20:20 Comment(0)
B
2

There is a more correct and dynamic solution: you must define the type of myFunction (as 'function') in argTypes, parameter of Meta.

This way you can configure a specific value for myFunction in every story. You don't have to specify the template if the arg is a component's input and has the same name.

Here is your example in CSF 3:

type MyComponentArgs = MyComponent & { myFunction: () => void };

const meta: Meta<MyComponentArgs> = {
  title: 'My Great Component',
  component: MyComponent,
  argTypes: {
    myFunction: { type: 'function', control: false },
  },
};
export default meta;

type Story = StoryObj<MyComponentArgs>;

export const Primary: Story = {
  render: (args) => ({
    props: args,
    template: `<my-component (onClick)="myFunction()"></my-component>`
  }),
  args: {
    myFunction: () => { alert('clicked'); }
  }
}

Note: I don't know why but control: false is mandatory, at least today with storybook v8.1

Bucolic answered 24/6, 2024 at 14:43 Comment(0)
A
4

Ok, I literally figured it out directly after posting this... of course.

I just needed to assign it to the args object in the template function:

const Template: Story<any> = (args) => {

  // this
  args.myFunction = () => { alert('clicked'); };

  return {
    props: args,
    template: `<my-component (onClick)="myFunction()"></my-component>`
  }
};
Acanthaceous answered 17/3, 2022 at 20:55 Comment(3)
Doesn't work for me. ctx.myFunction is not a functionMcbroom
@Mcbroom i think the new version of storybook does it a bit different. ``` const template = `<my-component (onClick)="myFunction()"></my-component>`; export const StoryName = { render: ()=>({ template }), args: { myFunction: ()=>{ alert('clicked') } } }; ``` edit: formatting is being dumb, sorry.Acanthaceous
Thanks but I get the same error with that...Mcbroom
B
2

There is a more correct and dynamic solution: you must define the type of myFunction (as 'function') in argTypes, parameter of Meta.

This way you can configure a specific value for myFunction in every story. You don't have to specify the template if the arg is a component's input and has the same name.

Here is your example in CSF 3:

type MyComponentArgs = MyComponent & { myFunction: () => void };

const meta: Meta<MyComponentArgs> = {
  title: 'My Great Component',
  component: MyComponent,
  argTypes: {
    myFunction: { type: 'function', control: false },
  },
};
export default meta;

type Story = StoryObj<MyComponentArgs>;

export const Primary: Story = {
  render: (args) => ({
    props: args,
    template: `<my-component (onClick)="myFunction()"></my-component>`
  }),
  args: {
    myFunction: () => { alert('clicked'); }
  }
}

Note: I don't know why but control: false is mandatory, at least today with storybook v8.1

Bucolic answered 24/6, 2024 at 14:43 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.