0

i'm trying to watch over a nested object, but it won't detect changes over it's properties, i know this has been asked before, and i tried with some solutions with no luck, so let me first explain in detail what i'm trying to do:

I have a multiselect input where you can choose multiple rooms for a reservation in a hotel:

enter image description here

So when you select rooms, the form creates new inputs for each room for detailing more information:

enter image description here

This is the code of that feature:

<div class="row container-fluid mr-auto ml-auto" v-for="room in extraRooms">
                <div class="col-4">
                  <ValidationProvider
                    name="Pax hab. adicional"
                    rules="required"
                    v-slot="{ passed, failed, errors }"
                  >
                    <base-input
                      :label="'Pax hab. * ' + room "
                      :error="errors[0]"
                      :class="[{ 'has-success': passed }, { 'has-danger': failed }]"
                    >
                      <el-select
                        :class="!!errors[0] ? 'select-danger' : 'select-primary'"
                        placeholder="Seleccionar"
                        filterable
                        collapse-tags
                        v-model="paxExtraRoom[room]"
                      >
                        <el-option
                          v-for="item in selects.paxListMin"
                          v-if="item <= paxAllowed[room]"
                          :label="item"
                          :value="item">
                        </el-option>
                      </el-select>
                    </base-input>
                  </ValidationProvider>
                </div>
                <div class="col-2">
                  <ValidationProvider
                    name="Adulto(s)"
                    rules="required|min:1|numeric|max_value:5|min_value:1"
                    v-slot="{ passed, failed, errors }"
                  >
                    <base-input
                      required
                      v-model="extraRoomsAges[room].adults"
                      label="Adultos"
                      placeholder="+18 años"
                      addon-left-icon="tim-icons icon-single-02"
                      type="text"
                      :error="errors[0]"
                      :class="[{ 'has-success': passed }, { 'has-danger': failed }]">
                    </base-input>
                  </ValidationProvider>
                </div>
                <div class="col-2">
                  <ValidationProvider
                    name="Teenagers"
                    rules="required|min:1|numeric|max_value:4"
                    v-slot="{ passed, failed, errors }"
                  >
                    <base-input
                      required
                      v-model="extraRoomsAges[room].teenagers"
                      label="Adolescentes"
                      placeholder="+12 a -18"
                      addon-left-icon="tim-icons icon-single-02"
                      type="text"
                      :error="errors[0]"
                      :class="[{ 'has-success': passed }, { 'has-danger': failed }]">
                    </base-input>
                  </ValidationProvider>
                </div>
                <div class="col-2">
                  <ValidationProvider
                    name="Niñ@s"
                    rules="required|min:1|numeric|max_value:4"
                    v-slot="{ passed, failed, errors }"
                  >
                    <base-input
                      required
                      v-model="extraRoomsAges[room].children"
                      label="Niñ@s"
                      placeholder="+3 a -11"
                      addon-left-icon="tim-icons icon-single-02"
                      type="text"
                      :error="errors[0]"
                      :class="[{ 'has-success': passed }, { 'has-danger': failed }]">
                    </base-input>
                  </ValidationProvider>
                </div>
                <div class="col-2">
                  <ValidationProvider
                    name="Infantes"
                    rules="required|min:1|numeric|max_value:4"
                    v-slot="{ passed, failed, errors }"
                  >
                    <base-input
                      required
                      v-model="extraRoomsAges[room].infants"
                      label="Infantes"
                      placeholder="-3 años"
                      addon-left-icon="tim-icons icon-single-02"
                      type="text"
                      :error="errors[0]"
                      :class="[{ 'has-success': passed }, { 'has-danger': failed }]">
                    </base-input>
                  </ValidationProvider>
                </div>
              </div>
            </div>

So in order to bind the v-model to each input, i create them in a dynamic mode by watching the multiselect for changes like this:

watch: {
    extraRooms(value){
      // this.extraRoomsAges = []
      value.forEach(val => {
        if (this.extraRoomsAges[val] === undefined){
          this.extraRoomsAges[val] = {
            room: val,
            adults: 1,
            teenagers: 0,
            children: 0,
            infants: 0
          }
        }
      })
    },
}

So what i need is to detect changes on the four small inputs in order to calculate the total of the numbers in those inputs to get the total pax in the left larger input, so i tried with another watcher like this:

extraRoomsAges: {
      handler(value){
        console.log(value)
        value.forEach(val => {
          this.paxExtraRoom[val.room] = parseInt(val.adults) + parseInt(val.teenagers) + parseInt(val.children) + parseInt(val.infants)
        })
      },
      deep: true
    }

But nothing happens, it won't detect any changes, any idea of how can i achieve this?

4
  • changes this.extraRoomsAges[val] = {...} to this.$set(this.extraRoomsAges, val, {...} Commented Aug 18, 2020 at 20:03
  • Thanks Sphinx, like this?: this.$set(this.extraRoomsAges[val] = { room: val, adults: 1, teenagers: 0, children: 0, infants: 0 }) Commented Aug 18, 2020 at 20:17
  • this.$set(this.extraRoomsAges, val, { room: val, adults: 1, teenagers: 0, children: 0, infants: 0 }); check Vue API Guide for more detail Commented Aug 18, 2020 at 20:18
  • Wow! thanks!, i didn't get the Syntax, now it's working!, can you please post it as an answer to mark it as the right one, thanks a lot! Commented Aug 18, 2020 at 20:22

1 Answer 1

1

From Vue Guide: Reactivity in Depth,

Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the Vue.set(object, propertyName, value) method. or vm.$set(object, propertyName, value)

So in your codes, the fix will be:

changes this.extraRoomsAges[val] = {...} to this.$set(this.extraRoomsAges, val, { room: val, adults: 1, teenagers: 0, children: 0, infants: 0 })

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.