Vue: How to access props data in created function? - vue.js

I'm passing an array of objects into a child component and I want to access this array into the created function of the child component.
When logging the entire this.$props object I'm getting all the data however when I'm logging the array I'm getting an empty proxy object.
Parent component
<script>
import SelectWithSearch from '#/components/formElements/SelectWithSearch.vue';
import AddressService from '#/services/AddressService';
export default {
data() {
return {
city: 312,
cityOptions: [],
};
},
components: { SelectWithSearch },
created() {
this.getCities();
},
methods: {
async getCities() {
const response = await AddressService.getCities();
this.cityOptions = response.data.cities.map((city) => {
return {
id: city.id,
display_name: `${city.sub_city} (${city.zip})`,
};
});
},
},
};
</script>
Child component (SelectWithSearch)
<script>
export default {
props: {
label: { type: String, required: false },
options: { type: Array, required: true },
},
created() {
console.log(this.$props);
console.log(this.$props.options);
console.log(this.options);
console.log(this.label);
},
Output
How can I access the options data in the created function?

Related

how to create vue-shepperd component

I am trying to develop guided tour with shepherd: https://www.npmjs.com/package/vue-shepherd but I cannot get the element. So here is my component for guide tour:
<template>
<div></div>
</template>
<script>
import { useShepherd } from 'vue-shepherd';
export default {
props: {
element: {
required: true,
},
id: {
type: Number,
required: true,
},
title: {
type: String,
},
text: {
type: String,
required: true,
},
position: {
type: String,
required: true,
},
},
mounted() {
this.tour.start();
},
data() {
return {
tour: null,
};
},
methods: {
createTour() {
this.tour = useShepherd({
useModalOverlay: true,
});
this.tour.addStep({
title: this.title,
text: this.text,
attachTo: { element: this.element, on: this.position },
buttons: [
{
action() {
return this.back();
},
classes: 'shepherd-button-secondary',
text: 'Back',
},
{
action() {
return this.next();
},
text: 'Next',
},
],
id: this.id,
});
this.tour.start();
},
},
created() {
this.createTour();
},
};
</script>
and here is my parent component:
<button ref="button">
Click
</button>
<guide :element="element" :title="'Tour'" :text="'Example'" :position="'bottom'" :id="1" />
and the mounted of the parent element:
mounted() {
this.element = this.$refs.button;
},
but the tour doesnt attach the the button element. it just appears in the middle of the page. Why do you think it is?
Looks like a usage problem in vue hooks. The child component's hooks fire before the parent component's hooks. Therefore, at the time of the creation of the tour, the element does not exist. Vue-shepherd does not use vue reactivity.
Use
mounted() {
this.$nextTick(() => {
this.createTour();
});
},
Codesanbox
But it's better to change the component structure. If you are using vue3 you can use my package
In this case it will look like this
<template>
<button v-tour-step:1="step1">
Click
</button>
</template>
<script>
import { defineComponent, inject, onMounted } from "vue";
export default defineComponent({
setup() {
const tour = inject("myTour");
onMounted(() => {
tour.start();
});
const step1 = {
/* your step options */
}
return {
step1,
};
}
});
</script>

Vue 3 chart js cause Cannot read properties of null (reading 'getContext')?

I have button which toggle data passed to this ChartComponent. If hold any seconds after toggle and retoggle so its work but if we doing it a bit fast, it is cause
Cannot read properties of null (reading 'getContext')? error.
<template>
<canvas></canvas>
</template>
<script>
import { defineComponent } from 'vue'
import Chart from 'chart.js/auto'
export default defineComponent({
name: 'ChartComponent',
props: {
type: {
type: String,
required: true,
},
data: {
type: Object,
required: true,
},
options: {
type: Object,
default: () => ({}),
},
},
data: () => ({
chart: null,
}),
watch: {
data: {
handler() {
this.chart.destroy()
this.renderChart()
},
deep: true,
},
},
mounted() {
this.renderChart()
},
methods: {
renderChart() {
this.chart = new Chart(this.$el, {
type: this.type,
data: this.data,
options: this.options,
})
},
},
})
</script>
You should unwrap/unproxy this.chart before accessing it by using Vue3 "toRaw" function:
import { toRaw } from "vue";
...
watch: {
data: {
handler() {
toRaw(this.chart).destroy()
this.renderChart()
},

Data not being passed from Child Data to Parent Props

I have a Request Form Component, and within this request form Component I have a Dropdown Menu Component, which I will link both below. All values in my table are pushed into an object upon hitting the Submit Button. However my dropdown selection is only being picked up by my console.log and not being pushed into the Object.
I'm not so familiar with Vue, so I'm not sure what direction to go in for fixing this. I'll attach the relevant (?) pieces of code below.
Parent Component:
<SelectComponent :selected="this.selected" #change="updateSelectedValue" />
export default {
fullScreen: true,
name: 'CcRequestForm',
mixins: [BaseForm],
name: "App",
components: {
SelectComponent,
},
data() {
return {
selected: "A",
};
},
props: {
modelName: {
default: 'CcRequest',
},
parentId: {
type: Number,
default: null,
},
},
mounted() {
this.formFields.requester.value = this.currentRequesterSlug;
},
destroyed() {
if (!this.modelId) return;
let request = this.currentCcRequest;
request.params = request.params.filter(p => p.id)
},
computed: {
...mapGetters(['ccTypesForRequests', 'currentRequesterSlug', 'currentCcRequest']),
ccTypesCollection() {
return this.ccTypesForRequests.map((x)=>[x.slug, this.t(`cc_types.${x.slug}`)]);
}
},
methods: {
addParam() {
this.addFormFields(['params'], {
slug: '',
name: '',
isRequired: true,
description: '',
typeSlug: '',
selected: ''
});
},
deleteParam(idx){
this.removeFormFields(['params', idx]);
},
restoreParam(idx){
this.restoreFormFields(['params', idx])
},
$newObject() {
return {
slug: '',
name: '',
isAbstract: false,
requester: '',
description: '',
status: 'inactive',
params: [],
selected: ''
};
},
$extraPrams() {
return {
parentId: this.parentId,
};
},
updateSelectedValue: function (newValue) {
this.selected = newValue;
},
},
watch: {
selected: function (val) {
console.log("value changed", val);
},
},
};
Child Component:
<script>
export default {
name: "SelectComponent",
props: {
selected: String,
},
computed: {
mutableItem: {
get: function () {
return this.selected;
},
set: function (newValue) {
this.$emit("change", newValue);
},
},
},
};
You have to define the emit property in the parent component, or else it won't know what to expect. That would look like:
<SelectComponent :selected="this.selected" #update-selected-value="updateSelectedValue" />
Check out this tutorial for more information: https://www.telerik.com/blogs/how-to-emit-data-in-vue-beyond-the-vuejs-documentation
To update selected property inside the object, in this constellation, you need to update object property manually upon receiving an event, inside of updateSelectedValue method. Other way could be creating a computed property, since it's reactive, wrapping "selected" property.
computed: {
selectedValue () {
return this.selected
}
}
And inside of object, use selectedValue instead of selected:
return {
...
selected: selectedValue
}

How to pass an object directly in a prop through Vue Router?

In Vue JS3, my Vue component, I can pass props like this: Parent:
<script>
export default {
data() {
return {
links: [],
};
},
methods: {
editLink(el) {
this.$router.push({
name: "EditLink",
params: {
id: el.id,
short_link: el.short_link,
long_link: el.long_link,
},
});
},
},
};
</script>
Component:
<script>
export default {
props: ["elem"],
data() {
return {
link: {},
};
},
mounted() {
this.link = {
id: this.$route.params.id,
short_link: this.$route.params.short_link,
long_link: this.$route.params.long_link,
};
},
};
</script>
But If I pass the Object named el directly like this:
this.$router.push({
name: "EditLink",
params: {
elem: el,
},
});
When I try to print it out, I get the value of elem as [Object Object], instead of an actual object. Why is this happening? What's the solution?
Try out to spread the el instead of assigning each value to the respective key :
this.$router.push({
name: "EditLink",
params: {...el},
});
then in the target page :
mounted() {
this.link = {...this.$route.params};
},

I want to watch to the value of the parent component in the child component

I have a parent component that sends tabs selected by the user to the
child component
I want to watch the value passed by the parent
component in the child component
I am sure that the value of tabs
will change according to the parent component selection
In this code, console isn't work
child component
props: {
tab: ''
},
data: function () {
return
tabs: this.tab,
};
},
watch: {
tabs: function () {
console.log('tabs', this.tabs);
},
},
parent component
<table
:tab="0">
</table>
in
data: function () {
return
tabs: this.tab,
};
},
the tabs property takes only the initial value, I recommend to use a computed property instead of data :
props: {
tab: ''
},
computed:{
tabs(){
return this.tab;
}
},
watch: {
tabs: function () {
console.log('tabs', this.tabs);
},
},
or you could watch the prop directly :
props: {
tab: ''
},
watch: {
tab: function () {
console.log('tab', this.tab);
},
},
Note that you shouldn't use HTML native elements as vue component like table
if the prop is an object or an array you should add deep option like :
props: {
tab: ''
},
computed:{
tabs(){
return this.tab;
}
},
watch: {
tabs:{
handler: function () {
console.log('tabs', this.tabs);
},
deep:true
}
},
An alternate approach
props: {
tab: {
type: Number,
default: 0
}
},
data() {
return {
tabs: this.tab,
};
},
watch: {
tab(newVal) {
this.tabs = newVal;
console.log('tabs', newVal);
},
},