BootstrapVue b-col formatting not working in child component - vuejs2

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

Related

In Vue, when do child components render?

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

degree symbol not being rendered by vue component

I have a vue component which displays a gauge. I need to include units on the display and have this as one of the props of the component. However, because there are a number of gauges with different formatting it is all stored in a vuex store that reads its settings from an API. This all works nicely apart from when I want to bring special symbols (such as degree signs) across. The vuex object is storing the formatting object as:
{"min":0,"max":50,"dp":1,"units":"°C"}
and I use it in my component as follows:
<svg-gauge v-else
v-bind:g-value="device.value"
v-bind:g-min="device.format.min"
v-bind:g-max="device.format.max"
v-bind:g-decplace="device.format.dp"
v-bind:g-units="device.format.units"
>
The problem is that this simply displays °C rather than a degree symbol. If I hard code the last line as
g-units="°C"
It all works as expected. I suspect it is that I am having to use v-bind to pass the property and this is messing things up. Is there a way to ensure that v-bind is treating my characters as I would like?
EDIT: Here is the svg-gauge component template where the units are actually rendered.
<template>
<b-row>
<b-card no-body class="bg-dark text-light border-0" align="center">
<b-card-body class="m-0 pt-0 pb-0">
<h5><slot name="title">Title</slot></h5>
<div class="row mini-gauge pt-3" align="center">
<vue-svg-gauge
class="mini-gauge"
:start-angle="-90"
:end-angle="90"
:value="gValue"
:separator-step="0"
:min="gMin"
:max="gMax"
base-color="#595959"
:gauge-color="[{ offset: 0, color: '#347AB0'}, { offset: 100, color: '#D10404'}]"
:scale-interval="5"
>
<div style="line-height: 11rem">{{gValue.toFixed(gDecplace)}} {{gUnits}}</div>
</vue-svg-gauge>
</div>
<div class="row mini-gauge">
<div class="col" align="left">{{gMin}}</div>
<div class="col" align="right">{{gMax}}</div>
</div>
</b-card-body>
</b-card>
</b-row>
</template>
Change this line to have a span with a v-html. Then in the v-html pass the gUnits prop
<div style="line-height: 11rem">
{{gValue.toFixed(gDecplace)}}
<span v-html="gUnits"></span>
</div>
You can find the reason by looking here.
Hope this helps!

How do i filter based on comparison on two arrays?

So, i have two arrays. One contains some appointments which all state what day they are scheduled for. In another array, i have the name of all the weekdays. I want to print only the weekdays with which there are appointments.
<b-col class="h-100">
<b-row v-for="day in week" class="schemaLine">
<div>{{day}}</div>
<b-row v-for="appointment in appointments" class="">
<div v-if="appointment.day === day && companies.includes(appointment.company)">
<b-button class="appointmentBlock w-100 m-2">
<div class="appointmentTitle">
{{appointment.name}}
</div>
<div class="appointmentTime">
{{appointment.time}}
</div>
</b-button>
</div>
</b-row>
</b-row>
</b-col>
The easiest way to only print the days you have at least one appointment for, is to pre-process your appointments. This has the added benefit of not requiring you to go over every appointment for every day of the week.
To get started, we create a computed property appointmentsPerDay, which maps a day to an array of appointments. Then we create another computed property that takes the keys of that object and sorts them so you can loop over them:
computed: {
appointmentsPerDay () {
// We assume that you get the appointments variable somehow
const appointmentsPerDay = {};
for (const appointment of this.appointments) {
const { day } = appointment;
// We initialise an array if no such array exists
if (!appointmentsPerDay[day]) {
appointmentsPerDay[day] = [];
}
// Now that it is guaranteed that we have an array, add our appointment to it
appointmentsPerDay[day].push(appointment);
}
return appointmentsPerDay;
},
visibleDays() {
const days = Object.keys(this.appointmentsPerDAy);
days.sort();
return days;
}
}
Now how do we use these?
<b-col class="h-100">
<b-row v-for="day in visibleDays" class="schemaLine">
<div>{{day}}</div>
<b-row v-for="appointment in appointmentsPerDay[day]" class="">
<div v-if="companies.includes(appointment.company)">
<b-button class="appointmentBlock w-100 m-2">
<div class="appointmentTitle">
{{appointment.name}}
</div>
<div class="appointmentTime">
{{appointment.time}}
</div>
</b-button>
</div>
</b-row>
</b-row>
</b-col>
As you can see, we just have to swap out some variables. You still see that we have to use a v-if to filter on companies. Obviously we can also pre-process that to eliminate the v-if entirely and just loop over the data that we actually want to show. I will leave that as an exercise for you.
i believe week is your weekdays array if so then it should be like this :
<b-row v-for="day in week" class="schemaLine" v-if="appointments.find(app => app.day === day)">

How to push an object to another Vue component

I'm using Element UI library with Vuejs framework (configured using Vue CLI).
I currently have a nested input form that is taking information and pushing it to an object array inside of a parent component, but I'm having a lot of trouble sharing this information to a child component.
I believe using props is the correct approach, but I'm not sure I'm declaring the props correctly. I also have the parent / child set up with vue-router.
Form in parent component...
<div>
<el-dialog title="Create a new space to huddle" :visible.sync="createHuddleVisible" width="1000px" height="200%">
<el-form :huddle="huddle" :index="index">
<el-form-item label="Huddle Headline" :label-width="formLabelWidth">
<el-input v-model="newHuddle" autocomplete="off" placeholder="What should we call this meeting?"></el-input>
</el-form-item>
<el-form-item label="Goal" :label-width="formLabelWidth" :autosize="{ minRows: 1, maxRows: 2 }">
<el-input type="textarea" v-model="newGoal" placeholder="Use this text box to quickly establish the goal of this huddle.">
</el-input>
</el-form-item>
<el-form-item label="Body" :label-width="formLabelWidth">
<el-input style="white-space: pre-line;" type="textarea" :autosize="{ minRows: 10, maxRows: 15 }" v-model="newBody"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button #click="createHuddleVisible = false">Cancel</el-button>
<el-button type="primary" #click="addHuddle">Confirm</el-button>
</span>
</el-dialog>
</div>
The 'addHuddle' method successfully takes all strings and creates new objects.
I would like to use the data captured here and displayed in a child component.
For now, I've just been trying to print one of the object values onto a card as a test with no luck. Blank card.
<template>
<el-card class="huddle-box-card" shadow="always">
{{ huddle[0].goal }}
</el-card>
</template>
<script>
export default {
name: 'HuddleSpaceOne',
props: {
huddle: {
type: Object
},
index: {
type: Number
},
}
}
</script>

Bootstrap-vue modal open three times

I'm using bootstrap-vue package. In some component I have three card-flip components:
<b-row>
<b-col lg="4">
<card-flip :order="'fifth'"></card-flip>
</b-col>
<b-col lg="4">
<card-flip :order="'sixth'"></card-flip>
</b-col>
<b-col lg="4">
<card-flip :order="'seventh'"></card-flip>
</b-col>
</b-row>
and inside this card-flip component I'm displaying three different buttons depending on :order prop:
<template>
<!-- some not related content -->
<template v-if="order === 'fifth'">
<button class="card-flip__button card-flip__button--2"
v-b-modal.modalStandard="">
Sprawdź ofertę1
</button>
</template>
<template v-if="order === 'sixth'">
<button class="card-flip__button card-flip__button--2"
v-b-modal.modalPremium="">
Sprawdź ofertę2
</button>
</template>
<template v-if="order === 'seventh'">
<button class="card-flip__button card-flip__button--2"
v-b-modal.modalPremiumPlus="">
Sprawdź ofertę3
</button>
</template>
<modal-standard></modal-standard>
<modal-premium></modal-premium>
<modal-premium-plus></modal-premium-plus>
</template>
I'm using this template syntax to not create unnecessary divs.
And issue is that when I click some of this button it open correct modal but three times on top of previous ones.
I'm adding correct id's to <b-modal> inside those modal-* components.
This is done because each modal is rendered three times, one for each card-flip. You should also add v-if="order === 'fifth'" etc also for each modal in your card-flip template.