Element: vuex and el-input without v-model

Created on 1 Dec 2016  ·  8Comments  ·  Source: ElemeFE/element

Versions:

  • Chrome: Version 55.0.2883.59 beta (64-bit)
  • Windows 10.1
  • "element-ui": "^1.0.2",
  • "vue": "^2.1.3",
  • "vuex": "^2.0.0"

### Reproduction Link

Steps to reproduce

i try to use vuex with el-input
the problem is i dont use a v-model because i cant mutate state outside from a mutation(strict)

  <el-input
        :value="item.description"
        @input="update($event, 'description', index)"
        type="textarea"
        :autosize="{ minRows: 1, maxRows: 4}"
        placeholder="Please input">
</el-input>



update(e, field, index)  {
        this.$store.commit('UPDATE_INVOICE_ARTICLE', { index, value: e.target.value, field })
}


// Mutation 
  [types.UPDATE_INVOICE_ARTICLE] (state, article) {
    var newValue = { [article.field]: article.value }
    Object.assign(state.invoiceArticles[ article.index ], newValue)
  },

What is Expected?

This works

<input type="text" :value="item.description" @input="update($event, 'description',index)"> 

What is actually happening?

vue.runtime.common.js?d43f:511 [Vue warn]: Error in watcher "currentValue"
(found in component <ElInput>)


Create.vue?71c5:233 Uncaught (in promise) TypeError: Cannot read property 'value' of undefined
    at VueComponent.update (eval at <anonymous> (client.js:1330), <anonymous>:236:83)
    at Proxy.boundFn (eval at <anonymous> (client.js:730), <anonymous>:125:14)
    at Object.input [as fn] (eval at <anonymous> (client.js:1588), <anonymous>:35:15)
    at VueComponent.eval (eval at <anonymous> (client.js:730), <anonymous>:2186:16)
    at VueComponent.Vue.$emit (eval at <anonymous> (client.js:730), <anonymous>:3183:16)
    at VueComponent.currentValue (eval at <anonymous> (client.js:1393), <anonymous>:3002:13)
    at Watcher.run (eval at <anonymous> (client.js:730), <anonymous>:1709:19)
    at flushSchedulerQueue (eval at <anonymous> (client.js:730), <anonymous>:1513:13)
    at Array.eval (eval at <anonymous> (client.js:730), <anonymous>:376:20)
    at nextTickHandler (eval at <anonymous> (client.js:730), <anonymous>:326:16)

or i just do it wrong

thx! awesome ui

question

Most helpful comment

I have this same issue. If you use :value you can't update the input (literally typing in the field). V-model is just not an option when using vuex. Vue's default behavior allows you to update the input value when using :value, so it's weird that this behavior would change.

All 8 comments

@input="update($event, 'description', index)"
first param of the input event handler is exactly the input current value instead of a event.

update(value, field, index) { this.$store.commit('UPDATE_INVOICE_ARTICLE', { index, value, field }) }

thx but this is undefined for me but the error is gone
this is what i have now from your example

```

<el-input

:value="item.description"
@input="update(val,'description', index)"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4}"
placeholder="Please input"
>

update(val, field, index) {
//const newValue = this.invoiceArticles[ index ]
console.log(val) //undefined
```

You can use watch a object to chang v-model mutation

watch:{
 "item.description":{
    handler(newVal){
      this.$store.commit(....)
   }
 } 
}

The advantage is that if you have multiple attributes to commit

"item":{
   handler(newVal){
     if(newVal.description){
        //TODO
     }
     if(newVal.name){
         //TODO
     }
     this.$store.commit(....)
  }
} 

i don't like use @input in vm to vuex

update(e, field, index)  {
        this.$store.commit('UPDATE_INVOICE_ARTICLE', { index, value: e, field })
}

@input return value not 'event', or you can use @input.native

@QingWei-Li inpute.native works the other not i have no idea why

@yelingfeng i tried to watch but i cant see any changes


I have this and each item has multiple fields
<tr v-for="(item,index) in invoiceArticles" :key="item.id"> //invoiceArticles is from the vuex getter in a computed prop
..table stuff 
 <el-input
                                :value="item.description"
                                @input.native="update($event,'description', index)"
                                type="textarea"
                                :autosize="{ minRows: 1, maxRows: 4}"
                                placeholder="Please input"
                        >
                        </el-input>
.. more fields (item.price,...)

//Watch i cant see any changes

 watch: {
      'invoiceArticles': {
       handler(newval) {

           console.log('hehehe')

       }

      }
    },


@yelingfeng i updated
this works but i cant use if to determine which is changed

    watch: {
      'invoiceArticles': {
        handler(newVal) {
          console.log(newVal)
          if (newVal.description) {
            console.log(newval) //second problem when i have more than 1 item i get the whole array^^
          }

        },
        deep: true,

      }
    },

/e ### I have a new IDEA i try to split i will tell you it does work or not xD

So i just splitted every row in a single component file
then on beforeMount i just make a deepClone maybe i can just use Object.assign i will later check
then i use v-model again and on update i update my clonedObject in the vuex store

thx

<style lang="sass" rel="stylesheet/scss">

</style>

<template>
    <tr>
        <td style="width: 20px;">
            <strong>{{pos+1}}.</strong>
        </td>
        <td class="table-name" style="width: 400px;">
            <el-input
                    v-model="ownItem.name"
                    @input="update"
                    type="textarea"
                    :autosize="{ minRows: 1, maxRows: 4}"
                    placeholder="Please input">
            </el-input>
        </td>
        <td class="table-price" style="width: 150px;">
            <el-input @input="update" v-model="ownItem.price" :min="0">
            </el-input>


        </td>
        <td class="table-qty" style="width: 100px;">
            <el-input-number @input="update" v-model="ownItem.qty" :min="0"></el-input-number>

        </td>
        <td class="table-total">
            <span class="table-text">{{ownItem.qty * ownItem.price  | formatMoney}}</span>
        </td>
        <td class="table-remove">
            <el-button type="danger" size="small" @click="removeArticle(index)"
                       icon="delete"></el-button>
        </td>
    </tr>
</template>

<script>

  import { cloneDeep } from 'lodash'

  export default {

    computed: {

      ownItem() {
        return Object.assign({}, this.item)
      }
    },

    name: 'InvoiceArticle',
    props: {
      item: {
        required: true,
        type: Object
      },
      pos: {
        required: true,
        type: Number
      }
    },
    data() {
      return {
        ownItem: {}
      }
    },

    methods: {
      update() {
        this.$store.commit('UPDATE_INVOICE_ARTICLE', { index: this.pos, item: this.ownItem })
      }
    }
  }

</script>

I have this same issue. If you use :value you can't update the input (literally typing in the field). V-model is just not an option when using vuex. Vue's default behavior allows you to update the input value when using :value, so it's weird that this behavior would change.

I found the discussion in this issue very difficult to understand. From my experience it seems that:

  • el-input does work with vuex. $event contains the literal content of the text field, not the DOM event. And you can use that to update your store. Just don't try $event.target.value because there's no such field.
  • :value does work and will react to value changes that are done in the store. AFAICS there's no need for manual watches.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

akaylh picture akaylh  ·  3Comments

sudo-suhas picture sudo-suhas  ·  3Comments

no5no6 picture no5no6  ·  3Comments

chao-hua picture chao-hua  ·  3Comments

fscardua picture fscardua  ·  3Comments