0

I have two components "number-iput" and "basket input". How i can watch props from number-input (value) in basket-input?

Number Input component:

<template lang="pug">
    .field
        .number-input
            button.number-input__btn(@click.prevent="minus")
                i.i.i-minus
            input(type="number" v-model="value"  @input="valuecheck")
            button.number-input__btn(@click.prevent="plus")
                i.i.i-plus
</template>
<script>
export default {
    name: "number-input",
    props: {
        value: {
            type: Number,
            default: 1
        },
        min: {
            type: Number,
            default: 1
        },
        max: {
            type: Number,
            default: 999999999
        },
        current: {
            type: Number,
            default: 1
        }
    },
    methods: {
        plus() {
            if(this.value < this.max)  this.value++;
        },
        minus() {
            if(this.value > this.min) this.value--;
        },
        valuecheck() {
            if(this.value > this.max) this.value = this.max
        }
    },
    watch: {
        value: function() {
            if(parseInt(this.value) > parseInt(this.max)) this.value = this.max
        }
    }
}
</script>

Basket-input

<template lang="pug">
    .basket-item
        a.basket-item__image(href="")
            img(:src="image", :alt="title")
        .basket-item__info
            span.basket-item__caption {{ code }}
            a.basket-item__title(href="") {{ title }}
            span.basket-item__instock(v-if="instock && instock > 0") В наличии ({{ instock }} шт)
            span.basket-item__instock(v-else) Нет в наличии
        .basket-item__numbers
            number-input(min="1" max="99" :value="numberofitems")
        .basket-item__lastcol
            .column-price(v-if="price")
                b {{ numberofitems * price }} ₽
                span(v-if="numberofitems > 1") {{ numberofitems }} × {{ price }} ₽
            button.basket-item__remove Удалить товар
</template>
<script>
export default {
    name: 'basketitem',
    props: {
        image: {
            type: String,
            required: true
        },
        title: {
            type: String,
            required: true
        },
        code: {
            type: String,
            required: true
        },
        instock: {
            type: Number
        },
        price: {
            type: Number
        },
        numberofitems: {
            type: Number,
            default: 1
        }
    },

}
</script>

In basket input i need to watch number-input(value) and write it in numberofitems prop.. Im trying all, but my knowledge of vue is too low for that (

1 Answers1

2

Props are mechanism to pass data only in one way - that means you can pass a value from parent to child but child is not allowed to change the value. If you do, Vue will warn you.

Way around it to use events. The principle is wildly know as "props-down, events-up".

  1. You pass value to Child via prop
  2. When Child want to change the value, instead of changing it directly, it will emit the event with new value
  3. Parent component needs to handle that event and change its internal value (change will propagate into child item via prop)

You can read about various ways to do it for example here

Computed properties can help with that:

<template>
  <input type="number" v-model="internalValue" />
</template>
<script>
export default {
  props: {
    value: {
      type: Number,
      default: 1
    }
  },
  computed: {
    internalValue: {
      get:  function() {
        return this.value
      },
      set: function(newValue) {
        this.$emit('valueChanged', newValue)
      }
    }
  }
}
</script>

And in your parent component:

<template>
  <mycomponent :value="value" @valueChanged="value = $event"/>
  <mycomponent :value="value" @valueChanged="onValueChanged"/>
</template>
<script>
export default {
  data: {
    value: 0
  },
  methods: {
    onValueChanged(newValue) {
      this.value = newValue;
    }
  }
}
</script>

Notes

  • with larger and more complicated applications it can be better to use some solutions with shared global state like Vuex
  • Your Basket-input component has same problem because its receives numberofitems via prop
tony19
  • 125,647
  • 18
  • 229
  • 307
Michal Levý
  • 33,064
  • 4
  • 68
  • 86