bencodezen / vue-enterprise-boilerplate

An ever-evolving, very opinionated architecture and dev environment for new Vue SPA projects using Vue CLI.
7.77k stars 1.32k forks source link

Can't set input props using Vuetify #141

Closed marceloavf closed 5 years ago

marceloavf commented 5 years ago

Hey @chrisvfritz, first of all thank you for this awesome boilerplate!

I'm using Vuetify to speed up development but I'm having some trouble when setting props to this input.

_base-input-text.vue

...
<template>
  <v-text-field
    :type="type"
    :class="$style.input"
    single-line
    outline
    v-bind="
      $attrs
      // https://vuejs.org/v2/guide/components-props.html#Disabling-Attribute-Inheritance
    "
    @input.native="$emit('update', $event.target.value)"
    v-on.native="
      $listeners
      // https://vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components
    "
  ></v-text-field>
</template>
...

When I try to test it by setProps, equals as you do, it doesn't work, only in this part because the rest works normally as well.

 FAIL  src/components/_base-input-text.unit.js
  ● @components/_base-input-text › works with v-model

    expect(received).toEqual(expected)

    Expected value to equal:
      "ccc"
    Received:
      "bbb"

      17 |     // Sets the input to the correct value when props change
      18 |     wrapper.setProps({ value: 'ccc' })
    > 19 |     expect(inputEl.value).toEqual('ccc')
         |                           ^
      20 |   })
      21 |
      22 |   it('allows a type of "password"', () => {

      at Object.toEqual (src/components/_base-input-text.unit.js:19:27)

If it's a specifically error from Vuetify itself you can close the issue without any problem. Thank you!

aburai commented 5 years ago

you don't set value on v-text-field, you i can't see the script part. so it is just a guess

marceloavf commented 5 years ago

you don't set value on v-text-field, you i can't see the script part. so it is just a guess

The rest of the code is exactly equals to this repository code

I tried to set the value by binding it but instead of receiving an "bbb" I receive nothing 😞

GreggOD commented 5 years ago

Source code doesnt have .native on the @input emit

try the following:

// change this line on the input
@input.native="$emit('update', $event.target.value)"

// to this (removing the .native)
@input="$emit('update', $event.target.value)"

#thatShouldWork

// now that you are using Vuetify and it models off @input you might want to change the emit to 
'input' and not 'update', but if the above change works then keep it as is but understand you are
 abstracting Vuetify's API and Events by wrapping them in this frameworks events.

// you could change Chris's 'update' event to the default 'input' event. That will keep you more inline
with Vuetify's events so you don't get confused between the two and just stick with one.
@input="$emit('input', $event.target.value)"
// if you do the change (changing update to input), you can remove this from the JS
  model: {
    event: 'update',
  }
// and you would have to update the test
// from
expect(wrapper.emitted().update).toEqual([['bbb']])
// to
expect(wrapper.emitted().input).toEqual([['bbb']])
marceloavf commented 5 years ago

Hey @GreggOD, thanks for the reply.

When I remove .native from @input this stop working:

 ● @components/_base-input-text › works with v-model

    expect(received).toEqual(expected)

    Expected value to equal:
      [["bbb"]]
    Received:
      undefined

    Difference:

      Comparing two different types of values. Expected array but received undefined.

      13 |     inputEl.value = 'bbb'
      14 |     inputWrapper.trigger('input')
    > 15 |     expect(wrapper.emitted().input).toEqual([['bbb']])
         |                                     ^
      16 |
      17 |     // Sets the input to the correct value when props change
GreggOD commented 5 years ago

@marceloavf no stress, im learning as much as you here - its fun :)

So you have changed the emit to check for 'input' event.

(wrapper.emitted().input)

did you change your emit to emit an input event? because in the boilerplate it emits 'update'

@input="$emit('input', $event.target.value)"

//not
@input="$emit('update', $event.target.value)"

Also Vuetifys @input event might emit a value and not the input element. So you could try this;

// change the $event.target.value to just $event
@input="$emit('input', $event)"
marceloavf commented 5 years ago

Always calm, stay calm @GreggOD 😆

The code is exactly as you said, changing the $event.target.value to $event and removing .native fix the problem! Thank you

Now we get back to the first one, haha!

 FAIL  src/components/_base-input-text.unit.js
  ● @components/_base-input-text › works with v-model

    expect(received).toEqual(expected)

    Expected value to equal:
      "ccc"
    Received:
      "bbb"

      19 |     wrapper.setProps({ value: 'ccc' })
    > 20 |     expect(inputEl.value).toEqual('ccc')
         |                           ^
      21 |   })
      22 |
      23 |   it('allows a type of "password"', () => {

      at Object.toEqual (src/components/_base-input-text.unit.js:20:27)
GreggOD commented 5 years ago

@marceloavf lol - we can only try 😆

ThinkingOutLoudHere

As a test make value a prop and bind it.

<template>
  <v-text-field
    :type="type"
    :class="$style.input"
    single-line
    outline
    v-bind="$attrs"
    :value="value"  <-- add this line

// and in the JS for props
  props: {
    value: String, <--- add this line
    type: {
      type: String,
      default: 'text',
      // Only allow types that essentially just render text boxes.
      validator(value) {
        return [
          'email',
          'number',
          'password',
          'search',
          'tel',
          'text',
          'url',
        ].includes(value)
      },
    },
  }
marceloavf commented 5 years ago

@GreggOD I tried it before and didn't work

Tried again after this fixes and test still fails 😞

chrisvfritz commented 5 years ago

From the API docs, it looks like the input event emits the value directly for v-model, so $emit('update', $event) might be more what you're looking for - or perhaps using the change event instead would work. It's unclear to me what the difference is between those two events in the doc.

marceloavf commented 5 years ago

I managed to fix the emit event with @GreggOD, but now I can't setProps to the component, strange is that when the component is being mounted it receives the props.

wrapper.setProps({ value: 'ccc' }) it's not working here 😞

GreggOD commented 5 years ago

I've tried to replicate and resolved this for you today but the .find('input') in my test is returning undefined. And I cant seem to get a way to track down the input to properly run the tests.

Sorry man, if these tests were working Im sure I would have found the answer for you.

chrisvfritz commented 5 years ago

Hm, this problem sounds more specific to Vuetify than this boilerplate, so I would try to open an issue there.