jtlindsey
jtlindsey

Reputation: 4863

Vue storybook example using v-model and template?

How do i use v-model in vue storybook? In my case, it's just a custom component that a end user can use with v-model. I have the following example:

const dateRange = [
  new Date('2014/5/14').toISOString(),
  new Date('2015/2/2').toISOString(),
]

const Template = (args, { argTypes }) => ({
  components: { DateRangePicker },
  data: () => ({ dateRange }),
  props: Object.keys(argTypes),
  template:
    '<DateRangePicker v-bind="$props" v-model="dateRange" @input="onInput" />',
})

export const Default = Template.bind({})

Default.args = {
  dateRange: [], // if i remove this line, error is gone but i can't use a different default value for v-model via the template and all stories use the same value for `dateRange`.
}

If i do the above, then i end up with the following error: The data property "dateRange" is already declared as a prop. Use prop default value instead.. I'm trying to write story cases with different examples of values passed in as v-model

Upvotes: 7

Views: 9664

Answers (1)

Larizza Tueros
Larizza Tueros

Reputation: 629

The problem is that you are defining two instances of the same variable dateRange, one as a data with data: () => ({ dateRange }), and one as a prop with v-bind="$props".

To fix this you'll need to remove the data or the prop.

If you remove the data, you'll have a different problem, and that will be that you're trying to modify the parent prop with a v-model. Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "dateRange"

If you remove the prop, you can't modify it with the value of the control or exporting different cases.

Solution

  1. Keep your prop dateRange for simplicity of creating different cases
  2. rename the v-model, watch the dateRage prop of any changes and update the v-model.
  3. You can decide to keep the bind with the dateRange or without it. *
const range = [
  new Date('2014/5/14').toISOString(),
  new Date('2015/2/2').toISOString(),
]

const Template = (args, { argTypes }) => ({
  components: { DateRangePicker },
  data: () => ({ range }),
  props: Object.keys(argTypes),
  template: '<DateRangePicker v-bind="propsWithoutRange" v-model="range" @input="onInput" />',
  watch: {
      dateRange(value) {
          if (value.length === 2) {
              this.range = value;
          }
      }
  },
  computed: {
      // *Optional
      propsWithoutRange() {
          const { dateRange, ...all } = this.$props;
          return all;
      }
  }
})

export const Default = Template.bind({})
Default.args = {
  dateRange: []
}

Upvotes: 6

Related Questions