Evgeny Ladyzhenskiy
Evgeny Ladyzhenskiy

Reputation: 151

VueJs // V-for with v-modal // Data update issue after button clicked

UPDATED!!! Full component's code added: I've inputs rendered via v-for loop. List of inputs depends on an API response. I need a "plus" and "minus" buttons to change input's value. I almost find a solution but value changes only on sibling input change but not on button click. Here is my code...

 <template>
  <div class="allPlaces" id="allPlaces">
    <div class="wiget__row wiget__row--top" id="topRow">
      <div class="wiget__details wiget__details--allPlaces">
        <div class="wiget__logo">
          <img class="wiget__img wiget__img--logo" width="28" height="30" src="../../img/kassy_logo_img.png" alt="">
          <img class="wiget__img wiget__img--logoTXT" width="59" height="28" src="../../img/kassy_logo_text.png" alt="">
        </div>
        <div class="wiget__eventDetails">
          <p class="wiget__eventName">{{this.show[0].title}}</p>
          <div class="wiget__place">
            <span class="wiget__venue">{{this.building[0].title}}, </span>
            <span class="wiget__venueHall">{{this.hall[0].title}}</span>
          </div>
          <div class="wiget__dateOfEvent">
            <span class="wiget__time">{{this.getTime(this.event[0].date)}}</span>
            <span class="wiget__date">{{this.getDate(this.event[0].date)}}</span>
          </div>
        </div>
      </div>
    </div>

    <div class="allPlaces__wrapper">
      <h1 class="allPlaces__title">Оформление заказа</h1>
      <p class="allPlaces__description">Для оформления заказа выберите нужное количество мест</p>
      <div class="allPlaces__content">
        <div class="allPlaces__entrance" v-for="(entrance, index) in places.entrance" :key="entrance.id">
          <div class="allPlaces__infoBlock">
            <div>
              <div class="allPlaces__available">
                <span class="allPlaces__label allPlaces__label--places">Доступно мест:</span>
                <span class="allPlaces__data">&nbsp{{entrance.vacant_places}}</span>
              </div>
              <div class="allPlaces__title allPlaces__title--entrance">{{getEntranceName(entrance)}}</div>
            </div>
            <div class="allPlaces__price">
              <span class="allPlaces__label">Цена: </span>
              <span class="allPlaces__data">{{entrance.price}}</span>
            </div>
          </div>

          <div class="allPlaces__orderBlock">
            <div class="allPlaces__inputBlock">
              <input class="allPlaces__input" type="number" name="amount" v-bind:id="tickets"
                    v-model="tickets[index]" @blur="showLabel($event, index)">
              <label class="allPlaces__label allPlaces__label--input"
                     @click="hideLabel($event, index)">Количество мест

              </label>
            </div>

            <div class="allPlaces__btnBlock">
              <button class="allPlaces__btn allPlaces__btn--minus" type="button" name="button"
                      @click="removeTicket(index)"></button>
              <button class="allPlaces__btn allPlaces__btn--plus" type="button" name="button"
                      @click="addTicket(index)">
              </button>
            </div>
            <button class="allPlaces__btn allPlaces__btn--confirm" type="button" name="button"
                  @click="addEntrancePlaceToCart(entrance, index)">
                  <img class="allPlaces__img allPlaces__img--cart" src="../../img/cartWhite.png" alt="Корзина">
                  <span class="allPlaces__text allPlaces__text--cart">В корзину</span>
            </button>
          </div>
        </div>
      </div>
    </div>

    <div class="wiget__row wiget__row--bottom" id="bottomRow">
       <div class="wiget__row">
         <div class="wiget__amountBlock">
           <span class="wiget__tickets">
             <span>Билеты:</span>
             <span class="wiget__amount wiget__amount--tickets">{{this.ticketsInCart.count}}</span>
             <span>шт.</span>
           </span>
           <div class="wiget__money">
             <span class="wiget__money wiget__money--label">Итого:</span>
             <p>
               <span class="wiget__amount wiget__amount--money">{{this.ticketsInCart.total}}&nbsp</span>
               <span class="wiget__amount wiget__amount--money">руб.</span>
             </p>
           </div>
         </div>
         <div class="wiget__btnBlock">
           <button class="wiget__btn wiget__btn--goToHall" type="button" name="button"
                   @click="goToHall()">
                 Выбрать на схеме
           </button>
           <button class="wiget__btn wiget__btn--confirm" type="button" name="button"
           @click="goToCartPage($event)">Оформить заказ</button>
         </div>
       </div>
       <div class="wiget__row wiget__row--service">
         <span class="wiget__service">Сервис предоставлен:</span>
         <a href="https://www.kassy.ru" class="wiget__company">Kassy.ru</a>
       </div>
     </div>
  </div>
</template>

<script>
import vueMethods from '../../mixins/methods'
import { mapState } from 'vuex'

export default {
  name: 'allPlaces',
  mixins: [vueMethods],
  data () {
    return {
      tickets: []
    }
  },
  mounted () {
    this.$nextTick(function () {
      window.addEventListener('resize', this.updateAllPlacesOnResize)
      this.setupAllPlaces()
    })
  },
  methods: {
    setupAllPlaces () {
      let allPlaces = document.getElementById('allPlaces')
      let topRow = document.querySelector('.wiget__row--top')
      let wrapper = document.querySelector('.allPlaces__wrapper')
      let bottomRow = document.querySelector('.wiget__row--bottom')

      let allPlacesHeight = allPlaces.clientHeight
      let topRowHeight = topRow.clientHeight
      let bottomRowHeight = bottomRow.clientHeight

      let wrapperHeight = allPlacesHeight - topRowHeight - bottomRowHeight
      console.log('topRowHeight ', topRowHeight)
      console.log('allPlacesHeight ', allPlacesHeight)
      console.log('bottomRowHeight ', bottomRowHeight)
      console.log('wrapperHeight ', wrapperHeight)
      wrapper.style.minHeight = wrapperHeight + 'px'
    },
    updateAllPlacesOnResize (event) {
      this.setupAllPlaces()
    },
    getEntranceName (entrance) {
      let sectionId = entrance.section_id
      let section = this.section
      let sectionName = section.filter(function (e) {
        return e.id === sectionId
      })

      return sectionName[0].title
    },
    addTicket (index) {
      console.log(this.tickets)
      console.log(this.tickets[index])
      this.tickets[index] = parseInt(this.tickets[index]) + 1
      return this.tickets
    },
    removeTicket (index) {
      this.tickets[index] = parseInt(this.tickets[index]) - 1
    },
    addEntrancePlaceToCart (entrance, index) {
      console.log('entrance.id to add to cart ', entrance.id)
      let db = this.db
      let places = parseInt(this.tickets[index])
      console.log('places ', places)
      console.log('index ', index)
      let sessionId = this.sessionId
      let entranceId = parseInt(entrance.id)
      let params = {db, places, sessionId, entranceId}
      this.$store.dispatch('addEntrancePlaceToCart', params) // Добавили место в корзину
    },
    goToHall () {
      this.$store.dispatch('closeAllPlaces')
      this.$store.dispatch('openHallPlan')
    },
    hideLabel (e, index) {
      console.log('CLICKED')
      console.log('index click', index)
      let input = document.getElementsByClassName('allPlaces__input')
      let target = e.target
      input[index].focus()
      console.log('this.tickets ', this.tickets)
      console.log(target)
      if (this.tickets === '') {
        target.style.display = 'block'
      } else {
        target.style.display = 'none'
      }
    },
    showLabel (e, index) {
      console.log('BLUR')
      console.log('index blur', index)
      let label = document.getElementsByClassName('allPlaces__label allPlaces__label--input')
      console.log(this.tickets[index])
      if (this.tickets[index] === '' || this.tickets[index] === undefined) {
        label[index].style.display = 'block'
      } else {
        label[index].style.display = 'none'
      }
    }
  },
  destroyed () {
    window.removeEventListener('resize', this.setupAllPlaces)
  },
  computed: {
    ...mapState({
      db: state => state.onload.currentDb,
      currentEvent: state => state.onload.currentEvent,
      modals: state => state.modals,
      metric: state => state.onload.eventData.metric,
      section: state => state.onload.eventData.section,
      show: state => state.onload.eventData.show,
      event: state => state.onload.eventData.event,
      building: state => state.onload.eventData.building,
      hall: state => state.onload.eventData.hall,
      places: state => state.onload.eventData.places,
      placesSeated: state => state.onload.eventData.places.place,
      sessionId: state => state.cart.sessionId,
      ticketsInCart: state => state.cart.ticketsInCart
    })
  }
}
</script>

<style scoped lang="stylus">
@import '../../styles/Root/allPlaces'
@import '../../styles/Root/wiget'
</style>

Please advise

enter image description here

Upvotes: 1

Views: 154

Answers (1)

mathk
mathk

Reputation: 8133

You tickets is not correctly initialized. The data populated a empty array but the template will add new element without using the VueJs way of adding reactivity.

What happen is similare to:

let tickets = [];
tickets[0] = ...;

In VueJs you should use push to insert an element to an array and not using the "sparse implementation".

So when your places is being populated inside your store you should create the tickets table from the size of it. Something similare to the following in a watcher or elsewhere depending on your need:

this.tickets = this.place.map(_ => 0);

Upvotes: 1

Related Questions