In Vue, when do child components render? - vue.js

I'm creating a calendar to track payments due. I have the following section of code to create the calendar grid. I am using Bootstrap-Vue:
<div v-for="week in 5">
<b-row class="pb-2">
<b-col class="px-2">
<Day
:day="first(week)"
:today=days[(week - 1) * 7]
:payments="payments"
></Day>
</b-col>
<b-col
v-for="(day, index) in days.slice((week - 1) * 7 + 1, week * 7)"
:key="index"
class="pr-2 pl-0"
>
<Day
:day="day"
:today="today"
:payments="payments"
></Day>
</b-col>
</b-row>
</div>
Day is a child component that renders the data and payments due for that day. The days prop is an array of moment.js variables. When I run this, no days are created for Sundays. I get the following error 5 times (one for each Sunday):
[Vue warn]: Error in render: "TypeError: Cannot read property 'date' of undefined"
If I change the assignment of the day prop for Sundays to:
:day="first(week)"
and then create a first method:
first(week) {
return this.days[(week - 1) * 7];
},
the calendar will be created correctly (after the screen flashes a few times). However, I still get the aforementioned errors. Why?
Day has a child component, Date, which is responsible for displaying the day's date.
<div
class="date"
:id="id"
:title="title"
>
{{ day.date() }}
</div>
This is where the error is generated.

The child components are mounted before the parent, although I am not sure it will actually help you solve your issue.

I think you should't mount the child component before obj get date attr

Related

Vue 3 - Composition API - TransitionGroup with slot

I have a transition group that render a list of element, i would like to add a component at the end as last list item. The last item is added via slot.
Everything works fine but i get a warning that says "TransitionGroup children must be keyed." I triend to put key attribute on the slot or directly on the component that use it but the warning still remain, any idea?
here my component:
<template>
<TransitionGroup name="list">
<CategoryListItem v-for="item in items" :key="item.id" />
<slot :key="items.length + 1"></slot>
</TransitionGroup>
</template>
how can i programmately assign a key to the component that will be added to the list via slot?

[Vue warn]: The data property “x” is already declared as a prop. BootstrapVue

Could someone kindly advise me what I am doing wrong here?
I am using BootstrapVue to create radio buttons, in second image. In spite of I even didn't declare “checked” prop, still getting the error, in first image, for every buttons and also every form-groups in the project.
<template>
<div>
<b-form-group
label-cols="auto"
label="Peer Groups:"
class="pg-button-group"
label-class="text-primary"
label-size="sm"
v-if="peerGroups"
>
<b-form-radio-group
v-model="selectedPg"
:options="peerGroups"
button-variant="primary"
#change="pgSelectedByClick"
buttons
size="sm"
class=""
>
</b-form-radio-group>
</b-form-group>
</div>
</template>
The Error I got:
Buttons which I try to create:

Vue changes to array not updating the DOM

I'm trying to make changes to an array in the parent component (insert and update data) that is passed to the child component via Props, but the DOM is not being updated.
Parent component:
<UsersList
v-for="(role, i) in userRolesNames"
:key="i"
:users="usersPages[i].data"
/>
Child component:
<template>
<div
v-for="user in users"
:key="user.id"
>
<span>{{ user.name }}</span>
<div>
<i
class="bi bi-pen-fill edit-icon m-pointer"
#click="onClickEdit(user)"
></i>
<i
class="bi bi-trash-fill delete-icon ms-2 m-pointer"
#click="onClickDelete(user)"
></i>
</div>
</div>
</template>
<script lang="ts">
// recieving the array
props: {
users: {
required: true,
type: Array as PropType<usersType[]>
}
}
</script>
Each user basically has the following structure:
{
id: x,
name: 'x',
email: 'x',
login: 'x',
role: x
}
The problem is that when trying to insert or update a record in the usersPages[i].data array, the DOM doesn't change. If I use the Vue developer tools, the data is changing correctly, but the DOM isn't.
Tried inserting using the push method on the array but without success. The only thing that worked was this:
const newUser = response.data;
const page = this.usersPages[newUser.role - 1];
Vue.set(page, 'data', [...page.data, newUser]);
To update I tried to directly change the user properties, but like the insert the DOM doesn't update. What worked was:
const page = this.usersPages[user.role - 1];
const oldUsers = page.data.filter(u => u.id != user.id);
Vue.set(page, 'data', [ ...oldUsers, response.data ]);
Works but doesn't look right... Can anyone help?
I had a similar problem before. I believe that this is a bug in vue. The reason for this is that Vue rendered the v-for already. Vue as of now does not know how to handle the changes in the array. What I did as a workaround for this is have a updateKey variable inside my script set to 0. Then increment this variable every time we update the array updateKey++. And we use this key for our component.
On child component,
<template>
<span
v-for="user in users"
:key="user.id"
>
<div :key="updateKey">
<span>{{ user.name }}</span>
<div>
<I
class="bi bi-pen-fill edit-icon m-pointer"
#click="onClickEdit(user)"
></i>
<I
class="bi bi-trash-fill delete-icon ms-2 m-pointer"
#click="onClickDelete(user)"
></i>
</div>
</div>
</span>
</template>
and onClickEdit(user) and onClickDelete(user) make sure you have updateKey++
The DOM won't update because you are not doing it reactively. To update this value reactively you should listen to some event (input for example), that you'll emit in the child component and pass the new(!) value to your property. But a better way is to bind your components via v-model.
P.S. - So you can see changes in the devtools because this is not a part of the Vue lifecycle, it`s just like a parser that watches actual data, but without context.
I decided to create an example to show #peperoneen how I did it, as I believed the way was correct. But in the example itself, it worked and in my project, it didn't, and the only difference was the way the list was initially filled.
To load the users I do a request to the API that returned the paged data, which I normally assigned with the '=' operator. However, I decided to do the assignment step by step and in the users part, I used the 'push' method. This way, the operations with the list using push and filter work normally, updating the DOM and without the need to use Vue.set
I think the problem was the way the list was being generated. I wasn't doing it reactively I guess...

BootstrapVue b-col formatting not working in child component

I'm creating a calendar with a bg-primary for the container. For each row (week), I use a b-row with class of pb-2. I then have individual b-col's for the days. The b-col for Sunday uses px-2 while the other days have pr-2 and pl-0. This gives me the gutter all around that I desire. If I put the code in my main component, everything works fine. However, if I pass an array for one week of days to the child component, no gutters show.
*** CalendarGrid.vue <script> ***
data() {
return {
days: [1, 2, 3, 4, 5, 6, 7],
};
},
*** CalendarGrid.vue <template> ***
<template>
<b-row class="pb-2">
<b-col class="px-2">
<Day>{{ days[0] }}</Day>
</b-col>
<b-col
v-for="(day, index) in days.slice(1)"
:key="index"
class="pr-2 pl-0"
>
<Day>{{ day }}</Day>
</b-col>
</b-row>
</template>
I want to use a child component to display the calendar days, since I have additional data and formatting to add to each day. Day vue, at this point simply displays the day value sent to it.
*** Day.vue ***
<template>
<div class="days text-right">
<slot></slot>
</div>
</template>
I have a child component called Week.vue, which I call I want to call from CalendarGrid.vue
<Week :days="days" />
Week.vue consists of the exact same template as above. The only difference is that days is an array prop.enter code here

Using component with slot inside v-for

I need to render a component with a slot inside a v-for loop like so:
<div v-for="(data,index) in myList" :key="index">
<datepicker v-model="data.thru">
<div slot="beforeCalendarHeader" #click="selectToday" class="today p-2 text-center">
Today
</div>
</datepicker>
</div>
and i get the following error:
[Vue warn]: Duplicate presence of slot "beforeCalendarHeader" found in the same render tree - this will likely cause render errors.
How i can use the componentns slot inside the loop?
Sample:
https://codepen.io/DivDax/pen/ajoWPY