Cant delete item from Table with el-dialog element ui - vue.js

I can't delete item because I can't pass the id of the row to the dialog , Please can I have some help? I've been stuck since yesterday ,
The Setup Script :
<Script setup>
//////
**
*
*
const props = defineProps({
items: Object,
})
const centerDialogVisible = ref(false)
const form = useForm()
const openDialog = (row) => {
////// how can i pass row id to the deletItem function ?///////
centerDialogVisible.value = true
}
const deleteItem = (id) => {
form.delete(route('items.destroy', id), {
preserveScroll: true,
onSuccess: () => closeModal(),
onFinish: () => form.reset(),
})
}
const closeModal = () => {
centerDialogVisible.value = false
form.reset()
}
the template :
<el-table :data="items.data" style="width: 100%" row-key="id">
<el-table-column prop="id" label="Id" width="180" />
<el-table-column fixed="right" label="Operations" width="200">
<template #default="scope">
<el-button size="small" type="danger" #click="openDialog(scope.row)">delete</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="centerDialogVisible" title="Warning" width="30%" center>
<span> It should be noted that the content will not be aligned in center by default </span>
<template #footer>
<span class="dialog-footer">
<el-button #click="centerDialogVisible = false">Cancel</el-button>
<el-button type="primary" #click="deleteItem"> Confirm </el-button>
</span>
</template>
</el-dialog>
thank you for helping me to complete the code of the openDialog function, if not if you have another method thank you

You can try by setting another ref to hold your id, and set this id in openDialog function:
const { ref } = Vue
const App = {
setup() {
const items = ref([{id: 1, name: 'aaa'}, {id: 2, name: 'bbb'}, {id: 3, name: 'ccc'}])
const centerDialogVisible = ref(false)
const id = ref(null)
const openDialog = (row) => {
id.value = row.id
centerDialogVisible.value = true
}
const deleteItem = () => {
items.value = items.value.filter(i => i.id !== id.value)
centerDialogVisible.value = false
id.value = null
}
const closeModal = () => {
centerDialogVisible.value = false
}
return {
items, closeModal, openDialog, centerDialogVisible, deleteItem
};
},
};
const app = Vue.createApp(App);
app.use(ElementPlus);
app.mount("#app");
<script src="https://unpkg.com/vue#next"></script>
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
<script src="https://unpkg.com/element-plus"></script>
<div id="app">
<el-table :data="items" style="width: 100%" row-key="id">
<el-table-column prop="id" label="Id" width="180"></el-table-column>
<el-table-column fixed="right" label="Operations" width="200">
<template #default="scope">
<el-button size="small" type="danger" #click="openDialog(scope.row)">delete</el-button>
</template>
</el-table-column>
<el-table-column prop="name" label="Name" width="180"></el-table-column>
</el-table>
<el-dialog v-model="centerDialogVisible" title="Warning" width="30%" center>
<span> It should be noted that the content will not be aligned in center by default </span>
<template #footer>
<span class="dialog-footer">
<el-button #click="centerDialogVisible = false">Cancel</el-button>
<el-button type="primary" #click="deleteItem"> Confirm </el-button>
</span>
</template>
</el-dialog>
</div>

Related

I encounterd this error "Invalid prop: type check failed for prop "categoryId". Expected Number with value 13, got String with value "13""

When I changed the props data type from String to Number, I get the error.
Although I checked again and again for strange parts, I couldn't find it.
I don't know why It worked well with String type.
In the code below,
CategoryHome is the parent Component of CategoryShow.
Could you tell me Where are mistakes in my code?
The blow image is screen design.
// CategoryShow.vue
<script setup>
import axios from "axios";
import { ref, watch} from "vue"
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const props = defineProps({
categoryId: {
//type: String,
type: Number
}
})
const categories = ref([])
const singleCategory = ref({})
const recipes = ref([])
const getCategory = () => {
return axios.get('/api/categories/' + props.categoryId)
}
const getCategories = () => {
return axios.get('/api/categories')
}
const getRecipes = () => {
return axios.get('/api/categories/' + props.categoryId + '/recipes/')
}
const getCategoriesAndCategoryAndRecipes = async () => {
const res1 = await getCategories()
const res2 = await getCategory()
const res3 = await getRecipes()
singleCategory.value = res2.data
recipes.value = res3.data
categories.value = res1.data
}
// when created (in lifecycel hook)
getCategoriesAndCategoryAndRecipes()
// when category page is changed,
watch(route, () => {
if (!isNaN(props.categoryId))
{
getCategoriesAndCategoryAndRecipes()
}
})
</script>
<template>
<div class="left-container">
<div class="form-box">
<h4 style="margin-bottom: 20px; margin-top: 10px">RECIPE HOUSE</h4>
<form method="post" v-on:submit.prevent="addCategory">
<input type="text" v-model="newCategory">
</form>
</div>
<ul class="category_ul">
<li v-for="category in categories" :key="category.id">
<button class="btn btn-danger" v-on:click="deleteCategory(category.id)">Delete</button>
<router-link :to="{name: 'category.show', params: {categoryId: category.id }}">
<span>{{ category.title }}</span>
</router-link>
</li>
</ul>
</div>
<div class="right-container">
<span class="icon">
<i class="fas fa-utensils fa-lg"></i>
</span>
<div>
<span>{{ singleCategory.title }}</span>
<form method="post" v-on:submit.prevent="addRecipe">
<input type="text" v-model="newRecipe">
</form>
<ul style="margin-top: 15px;">
<li v-for="recipe in recipes">
<router-link :to="{name: 'recipe.show', params: {recipeId: recipe.id}}">
<span>{{ recipe.title }}</span>
</router-link>
</li>
</ul>
</div>
</div>
</template>
// CategoryHome
<script setup>
// import axios from "axios"
import { onMounted, ref } from "vue"
import { useRouter } from 'vue-router'
const router = useRouter()
const newCategory = ref('')
let categoryId = ''
async function initial() {
try {
const res = await axios.get('/api/max')
categoryId = res.data.id
console.log(typeof categoryId) // number
router.push({name: 'category.show', params: { categoryId: categoryId }})
} catch(err) {
console.log('error handling')
}
}
initial()
</script>
<template>
<div class="left-container">
<h4 style="margin-bottom: 20px; margin-top: 10px">RECIPE HOUSE</h4>
<form method="post" v-on:submit.prevent="addCategory">
<input type="text" v-model="newCategory">
</form>
</div>
</template>
In CategoryHome, console.log(typeof categoryId) output number.
Are categoryId's data type in CategoryHome and categoryId's data type in props in CategoryShow not matching?
Thank you for your help.
I'm sorry My Englsh is not very good.

pagination destructuring assignment value setting error

I'm trying to use the pagination feature. I wrapped a ref about the page with params =ref , paginated with params in axios and decomposed the structure to define totalCount. But I don't know where the problem lies with the Uncaught(promise) TypeError:Cannot set properties of undefined(setting 'value') error in the console. What part of the code needs to be modified?
boardlist.vue
<template>
<div>
<table class="box">
<tbody>
<tr
v-for="forms in form"
:key="forms.id"
style="cursor: pointer;"
#click="NoticeDetail(forms.id)">
<td class="td_title">
{{ forms.title }}
</td>
<td class="text_center">
{{ forms.company }}
</td>
<td class="text_center">
{{ forms.company_url }}
</td>
<td class="text_center">
{{ forms.location }}
</td>
<td class="text_right">
{{ forms.date_posted }}
</td>
</tr>
</tbody>
<AppPagination
:current-page="params._page"
:page-count="pageCount"
#page="page => (params._page = page)" />
</table>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import Sidebar from '~/components/Sidebar.vue'
import { ref,computed,watchEffect } from 'vue'
import axios from 'axios'
import AppPagination from '~/components/AppPagination.vue'
const router = useRouter()
const form = ref([])
const params = ref({
_page: 1,
_limit: 10,
})
const totalCount = ref(0)
const pageCount = computed(() =>
Math.ceil(totalCount.value / params.value._limit),
)
const username = sessionStorage.getItem('user')
const fetchPosts = async (params) =>{
console.log(params)
axios.get('http://127.0.0.1:8000/jobs/all', {
params: {
params
}
})
.then((res)=>{
console.log(res.data)
const { totalCount, noticeList } = res.data;
form.value = noticeList;
totalCount.value = totalCount;
})
}
watchEffect(fetchPosts)
const NoticeWrite = () => {
router.push({
path: '/service_center/notice/notice_create',
})
}
const NoticeDetail = id => {
console.log(id)
router.push({
name: 'noticedetail',
params: {
id
}
})
}
</script>
pagination.vue
<template>
<nav
class="mt-5"
aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li
class="page-item"
:class="isPrevPage">
<a
class="page-link"
href="#"
aria-label="Previous"
#click.prevent="$emit('page', currentPage - 1)">
<span aria-hidden="true">«</span>
</a>
</li>
<li
v-for="page in pageCount"
:key="page"
class="page-item"
:class="{ active: currentPage === page }">
<a
class="page-link"
href="#"
#click.prevent="$emit('page', page)">{{
page
}}</a>
</li>
<li
class="page-item"
:class="isNextPage">
<a
class="page-link"
href="#"
aria-label="Next"
#click.prevent="$emit('page', currentPage + 1)">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
currentPage: {
type: Number,
required: true,
},
pageCount: {
type: Number,
required: true,
},
})
defineEmits(['page'])
const isPrevPage = computed(() => ({ disabled: !(props.currentPage > 1) }))
const isNextPage = computed(() => ({
disabled: !(props.currentPage < props.pageCount),
}))
</script>
<style lang="scss" scoped></style>

VueJs - Conditionaly showing elements in table

I have pretty simple table of users here with only 4 cols, and i want to show a button for each user depending on his status 'isActive'. If user is active i want to show button with text 'disable' and vice versa. I am little bit stuck with this because i dont have an idea how can i show these buttons, because i am using vuexy template for this project(admin panel). Is there a way to do this with JSX?
Please take a look at code, i am getting data from mysql with nodejs. Ask me if you need more info. Thanks.
<template>
<div>
<div class="container">
<b-card-text class="mb-2">
<div
v-if="showLoginError"
class="text-center bg-danger colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ loginError }}</span>
</div>
</b-card-text>
<b-card-text class="mb-2">
<div
v-if="showSuccessMessage"
class="text-center bg-success colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ successMessage }}</span>
</div>
</b-card-text>
<section id="card-actions" class="input-section">
<b-row>
<b-col cols="8">
<b-card-actions ref="cardAction">
<validation-observer ref="simpleRules">
<b-form>
<b-row>
<b-col md="6">
<b-form-group>
<validation-provider
#default="{ errors }"
name="First Name"
rules="required"
>
<b-form-input
v-model="name"
:state="errors.length > 0 ? false:null"
placeholder="Twitter username"
/>
</validation-provider>
</b-form-group>
</b-col>
<b-col cols="12">
<b-button
variant="primary"
type="submit"
#click.prevent="validationForm"
>
Submit
</b-button>
</b-col>
</b-row>
</b-form>
</validation-observer>
</b-card-actions>
</b-col>
</b-row>
</section>
// This is table
<b-table responsive="sm" :items="items"/>
</div>
</div>
</template>
<script>
import { ValidationProvider, ValidationObserver } from 'vee-validate'
import {
BFormInput, BFormGroup, BForm, BRow, BCol, BButton, BTable,
} from 'bootstrap-vue'
import { required } from '#validations'
import axios from 'axios'
import { getUserToken } from '#/auth/auth'
export default {
components: {
ValidationProvider,
ValidationObserver,
BFormInput,
BFormGroup,
BForm,
BRow,
BCol,
BButton,
BTable,
},
data() {
return {
name: '',
successMessage: '',
showSuccessMessage: false,
loginError: '',
showLoginError: false,
required,
items: [],
}
},
beforeMount() {
this.getAllUsers()
},
methods: {
getAllUsers() {
const API_URL = `${this.$server}/api/twitter/allusers`
const params = {
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data) {
res.data.forEach(element => {
let isActive = 'active'
if (element.isActive === 0) {
isActive = 'disabled'
}
const arr = {
twitter_name: element.twitter_name,
twitter_username: element.twitter_username,
twitter_id: element.twitter_id,
userActive: isActive,
}
this.items.push(arr)
})
}
})
},
validationForm() {
const API_URL = `${this.$server}/api/twitter/adduser`
const params = {
twitter_username: this.name,
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data.success) {
this.successMessage = res.data.message
this.showSuccessMessage = true
// Hide message after 5sec
setTimeout(() => {
this.successMessage = ''
this.showSuccessMessage = false
}, 5000)
} else {
this.loginError = res.data.message
this.showLoginError = true
// Hide message after 5sec
setTimeout(() => {
this.loginError = ''
this.showLoginError = false
}, 5000)
}
})
},
},
}
</script>
I'm a little bit confused, where do you want to show your button ?
If it's in the table, you can use the custom templation of Bootstrap-Vue, you'll find the doc here with an example : https://bootstrap-vue.org/docs/components/table#custom-data-rendering
EDIT: here an example for your case
<b-table responsive="sm" :items="items">
<template #cell(userActive)="data">
<b-button v-if="data.userActive">Disabled</b-button>
<b-button v-else>Enabled</b-button>
</template>
</b-table>

Using v-if loading with async es6

how can we make v-if loading work with an Async typo from Es6 with Vue?
here is the template, and I will put the solution also below, hope it helps.
this helped me so I know everyone learns differently so here is the way I understood things, less theoretical more practical, have a nice day!
<template>
<div class="container-fluid">
<v-col
md="6"
offset-md="3"
v-if="loading"
justify="center">
<v-progress-circular
:size="50"
color="blue"
indeterminate
>
</v-progress-circular>
</v-col>
<div v-else class="row">
<main role="main" class="col-md-12 ml-sm-auto col-lg-12 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 ">
<h2>Learning loading with async</h2>
</div>
</main>
</div>
</div>
</template>
<script>
import Row from '#/components/Row.vue';
const { GoogleSpreadsheet } = require('google-spreadsheet');
const creds = require('#/client_secret.json');
export default {
name: "Sheet",
components: {
Row
},
props: ["sheet"],
data() {
return {
rows: [], // your data things
}
},
methods:{
async accessSpreadSheet() {
const doc = new GoogleSpreadsheet('blahblahblah');
await doc.useServiceAccountAuth(creds);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
const rows = await sheet.getRows({
offset: 1
})
this.rows = rows;
}
},
created() {
this.accessSpreadSheet();
}
}
Example using v-if loading for skeleton loader or whatever, with async data method... I guess in vue
not perfect but i hope it helps out, I will just add the important parts:
<template>
<div class="container-fluid">
<v-col
md="6"
offset-md="3"
v-if="loading"
justify="center">
<v-progress-circular
:size="50"
color="blue"
indeterminate
>
</v-progress-circular>
</v-col>
<div v-else class="row">
<main role="main" class="col-md-12 ml-sm-auto col-lg-12 pt-3 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 ">
<h2>Learning loading with async</h2>
</div>
</main>
</div>
</div>
</template>
<script>
import Row from '#/components/Row.vue';
const { GoogleSpreadsheet } = require('google-spreadsheet');
const creds = require('#/client_secret.json');
export default {
name: "Sheet",
components: {
Row
},
props: ["sheet"],
data() {
return {
rows: [], // your data things
loading: true, //this is what matters
}
},
methods:{
async accessSpreadSheet() {
const doc = new GoogleSpreadsheet('blahblahblah');
await doc.useServiceAccountAuth(creds);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
const rows = await sheet.getRows({
offset: 1
})
this.rows = rows;
this.loading = false; //this is what works
}
},
created() {
this.accessSpreadSheet();
}
}

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>
Kassy.ru
</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
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);