Keep getting error "is not defined on the instance but referenced during render" - vue.js

I keep getting the following error after binding my data components to the template. Any help would be appreciated.
script:
data() {
return {
sireDetailsData: [],
horse_show_name_prop:,
}
},
async created () {
const psireName = await this.sireName;
console.log(psireName)
try {
const response = await sireDetails.fetchHorseIndex(psireName);
this.sireDetailsData = response.data;
try {
this.horse_show_name_prop = this.sireDetailsData[0].horse_details[0].horse_show_name
} catch (error) {
this.horse_show_name_prop = undefined
}
} catch (error) {
console.error(error);
}
},
template:
<a-col
:span="6"
:md="6"
align="middle"
style="margin-right: 0px;"
:horse_name="horse_show_name_prop"
>
<p
class="m-0 text-sm font-bold center"
style="min-width: 0px;"
v-if="horse_name !== undefined"
>
{{ horse_name }}%
</p>
<p
class="m-0 text-sm font-bold center"
style="min-width: 0px;"
v-else
>
-
</p>
<a-tag
class="ant-tag-primary font-semibold text-xs"
style="min-width: 30px;margin-right: 0px;"
>
Win %
</a-tag>
</a-col>
After making some live changes the data then loads in. It makes me think things are rendering out of order..

You need to declare horse_name in data:
data() {
return {
sireDetailsData: [],
horse_show_name_prop:,
horse_name: '', // Add horse_name here
}
},

Related

Cannot get computed property (array)

Trying to get a 'displayImages' array as a computed property. Using a default 'selected' property = 0.
this.selected changes accordingly on mouseover and click events.
When trying to get the computed 'displayImages' it says:
"this.variations[this.selected] is undefined."
I'm using an api to get my product data and images.
<template>
<div id="product-page">
<v-card width="100%" class="product-card">
<div class="image-carousel">
<v-carousel height="100%" continuos hide-delimiters>
<v-carousel-item
v-for="(image, i) in displayImages"
:key="i"
:src="image"
>
</v-carousel-item>
</v-carousel>
</div>
<div class="details">
<h2>{{ this.title }}<br />Price: ${{ this.price }}</h2>
<p>{{ this.details }}</p>
<ul style="list-style: none; padding: 0">
<li
style="border: 1px solid red; width: auto"
v-for="(color, index) in variations"
:key="index"
#mouseover="updateProduct(index)"
#click="updateProduct(index)"
>
{{ color.color }}
</li>
</ul>
<div class="buttons">
<v-btn outlined rounded
>ADD TO CART<v-icon right>mdi-cart-plus</v-icon></v-btn
>
<router-link to="/shop">
<v-btn text outlined rounded> BACK TO SHOP</v-btn>
</router-link>
</div>
</div>
</v-card>
</div>
</template>
<script>
export default {
name: "Product",
props: ["APIurl"],
data: () => ({
title: "",
details: "",
price: "",
variations: [],
selected: 0,
}),
created() {
fetch(this.APIurl + "/products/" + this.$route.params.id)
.then((response) => response.json())
.then((data) => {
//console.log(data);
this.title = data.title;
this.details = data.details.toLowerCase();
this.price = data.price;
data.variations.forEach((element) => {
let imagesArray = element.photos.map(
(image) => this.APIurl + image.url
);
this.variations.push({
color: element.title,
images: imagesArray,
qty: element.qty,
productId: element.productId,
});
});
});
},
computed: {
displayImages() {
return this.variations[this.selected].images;
},
},
methods: {
updateProduct: function (index) {
this.selected = index;
console.log(index);
}
},
};
</script>
To properly expand on my comment, the reason why you are running into an error is because when the computed is being accessed in the template, this.variations is an empty array. It is only being populated asynchronously, so chances are, it is empty when VueJS attempts to use it when rendering the virtual DOM.
For that reason, accessing an item within it by index (given as this.selected) will return undefined. Therefore, attempting to access a property called images in the undefined object will return an error.
To fix this problem, all you need is to introduce a guard clause in your computed as such:
computed: {
displayImages() {
const variation = this.variations[this.selected];
// GUARD: If variation is falsy, return empty array
if (!variation) {
return [];
}
return variation.images;
},
}
Bonus tip: if you one day would consider using TypeScript, you can even simplify it as such... but that's a discussion for another day ;) for now, optional chaining and the nullish coalescing operator is only supported by bleeding edge versions of evergreen browsers.
computed: {
displayImages() {
return this.variations[this.selected]?.images ?? [];
},
}
For avoid this kind of error, you must to use the safe navigation property.
Remember, it's useful just when the app is loading.
Try something like that:
<script>
export default {
name: 'Product',
computed: {
displayImages() {
if (this.variations[this.selected]) {
return this.variations[this.selected].images;
}
return [];
},
},
};
</script>

how to create autocomplete component in vue js?

I am facing an issue with my autocomplete component. whenever i type anything into the input field the input is reset.I mean it does not let me type anything.It just keeps getting reset before i could fully type anything.
main.js
Vue.component('g-autocomplete', {
props: ['list','value','title'],
data() {
return {
input: '',
}
},
template: `<template>
<div class="autocomplete">
<input style="font-size: 12pt; height: 36px; width:1800px; " type="text" v-model="input" #input="handleInput"/>
<ul v-if="input" >
<li v-for="(item, i) in list" :key="i" #click="setInput(item)" >
<!-- {{ autocompleteData }} -->
<template v-if="title!='manager'">
<div class="container">
<p>
<b>ID:</b>
{{item.id}}
</p>
<p>
<b>Description:</b>
{{item.description}}
</p>
</div>
</template>
<template v-else>
<div class="container">
<p>
<b>ID:</b>
{{item.id}}
</p>
<p>
<b>First Name:</b>
{{item.firstName}}
</p>
<p>
<b>Last Name:</b>
{{item.lastName}}
</p>
</div>
</template>
</li>
</ul>
</div>
</template>`,
methods: {
handleInput(e) {
console.log('inside handleInput')
this.$emit('input', e.target.value)
},
setInput(value) {
console.log('inside setInput')
this.input = value
this.$emit('click', value)
},
},
watch: {
$props: {
immediate: true,
deep: true,
handler(newValue, oldValue) {
console.log('new value is'+newValue)
console.log('old value is'+oldValue)
console.log('value inside handler'+this.value)
console.log('list inside handler'+this.list)
console.log('title inside handler'+this.title)
this.input=this.value
}
}
// msg(newVal) {
// this.msgCopy = newVal;
// }
}
})
i reuse the above component from diffrent vue pages's like this-
<b-field label="Custom Business Unit">
<g-autocomplete v-on:input="getAsyncDataBusinessUnit" v-on:click="(option) => {updateValue(option.id,'businessUnit')}" :value="this.objectData.businessUnit" :list="dataBusinessUnit" title='businessUnit' >
</g-autocomplete>
</b-field>
my debounce function that is called when something is typed into the input field.
getAsyncDataBusinessUnit: debounce(function(name) {
if (!name.length) {
this.dataBusinessUnit = [];
return;
}
this.isFetching = true;
api
.getSearchData(this.sessionData.key,`/businessunit/?filter={id} LIKE '%25${name}%25' OR {description} LIKE '%25${name}%25'`)
.then(response => {
this.dataBusinessUnit = [];
response.forEach(item => {
this.dataBusinessUnit.push(item);
});
})
.catch(error => {
this.dataBusinessUnit = [];
throw error;
})
.finally(() => {
this.isFetching = false;
});
}, 500),
what could be the issue here ? Also i noticed that the issue doesn't happen if i comment out the body of the debounce function.So therefore i feel there is something in the debounce function that is causing this.I will try to isolate the problem but i want to understand what exactly is causing this issue. Plz help?

Vue el-form dynamic validation

<template>
<div>
<el-form label-position="top" :model="notificationEmails" ref="emailForm">
<el-form-item
v-for="(item, index) in notificationEmails.emails"
:key="index"
:label="getLabel(index)"
:for="`${item.id}_${index}`"
:prop="'emails.' + index + '.id'"
:rules="{
required: true,
type: 'email',
message: 'Not valid email',
trigger: ['blur', 'change']
}"
>
<el-row>
<el-col :span="6">
<el-input v-model="item.id" type="email" :id="`${item.id}_${index}`" />
</el-col>
<el-col :span="2" style="padding-left: 18px">
<span v-if="index === 0" tabindex="0" #click="addEmail" #keyup.enter.stop="addEmail">
<i aria-hidden="true" class="icon-add-circle-outline" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.addEmail')}}</span>
</span>
<span
v-else
tabindex="0"
#click="deleteEmail(item.id)"
#keyup.enter.stop="deleteEmail(item.id)"
>
<i class="icon-subtract-circle-outline" aria-hidden="true" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.deleteEmail')}}</span>
</span>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'EmailWidget',
data() {
return {
notificationEmails: {
emails: []
}
};
},
props: ['passEmail'],
watch: {
passEmail: {
handler(newVal) {
this.notificationEmails.emails = newVal;
},
deep: true
},
notificationEmails: {
handler() {
this.$refs.emailForm.validate(async validate => {
if (validate) {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: true
});
} else {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: false
});
}
});
},
deep: true
}
},
methods: {
addEmail() {
this.notificationEmails.emails.push({
id: '',
priority: this.notificationEmails.emails.length + 1
});
// this.emails = [...this.emails, { id: '', priority: this.emails.length + 1 }];
},
deleteEmail(email) {
// this.emails = this.emails.filter(item => item.id !== email);
let index = 0;
for (let i = 0; i < this.notificationEmails.emails.length; i += 1) {
if (this.notificationEmails.emails[i].id === email) {
index = i;
break;
}
}
this.notificationEmails.emails.splice(index, 1);
},
getLabel(index) {
return index === 0 ? this.$t('settings.soldTo.notif.email') : '';
}
},
};
</script>
<style lang="scss">
i:hover {
cursor: pointer;
}
</style>
Some problems about the validation in dynamic add or delete the emails in el-form of Vue. When I add a new email, the validation cannot work. When I delete email. it shows
Error: please transfer a valid prop path to form item!
There is no issue when I edit the email.
I change the props according to enter code here the official document, but it still shows error.

Nuxt Failed to execute ‘appendChild’ on ‘Node’ when trying to get window size

The problem is that the project must be transferred to Nuxt and some of the code does not work. Namely, the size of the screen must perform actions with the text. Since Nuxt is an SSR, the code cannot be executed on the server side because it does not know the size of the window.
Can I somehow fulfill this idea so that everything works?
I have a project with nuxt and i18n
[nuxt] Error while initializing app DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
at Object.Je [as appendChild]
this my component vue
This code is an example of what causes an error.
<template>
<section>
<div>
<h2 class="subtitle" v-html="filterHeadSlogan"></h2>
</div>
</section>
</template>
<script>
export default {
name: 'testapp',
data() {
return {
filterHeadSlogan: '',
windowWidth: 0
}
},
methods: {
getWindowWidth(event) {
this.windowWidth = document.documentElement.clientWidth
var str = "<i>HELLO WORLD</i>"
if (this.windowWidth >= 960) {
this.filterHeadSlogan = str
} else {
this.filterHeadSlogan = str.replace(/<\/?[^>]+(>|$)/g, '')
}
}
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
//Init
this.getWindowWidth()
})
}
}
</script>
An error occurred because there was no data in the variable. The village appeared, but there was no data and there was a conflict. I created asyncData
async asyncData(){
return {
headSlogan: ""
}
},
Full code
<template>
<div class="westartslogan">
<div class="head-slogan">
<h2 v-html="headSlogan"></h2>
</div>
<h3>{{$t('page.home.wellcom_block_subtitle_left')}}</h3>
<ul>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_1_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_2_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_3_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_4_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_5_left')"></div></li>
</ul>
<div class="startcalc-btn button-container">
<nuxt-link :to="getLocalizedRoute({ name: 'calculator' })" class="uk-button uk-button-default">{{
$t('page.home.wellcom_button_calculator') }}
</nuxt-link >
</div>
<div class="ourproject-btn uk-hidden#s">
<div class="button-container">
<nuxt-link :to="getLocalizedRoute({ name: 'portfolio' })" class="uk-button uk-button-default">
{{ $t('page.home.wellcom_button_portfolio') }}
</nuxt-link>
</div>
</div>
</div>
</template>
<script>
export default {
async asyncData(){
return {
headSlogan: ""
}
},
name: 'we_can',
data () {
return {
filterHeadSlogan: '',
headSlogan: this.$i18n.t('page.home.wellcom_block_title_left'),
windowWidth: 0
}
},
methods: {
getWindowWidth (event) {
this.windowWidth = document.documentElement.clientWidth
if (this.windowWidth >= 960) {
this.headSlogan = this.headSlogan
} else {
var str = this.headSlogan
this.headSlogan = str.replace(/<\/?[^>]+(>|$)/g, '')
}
}
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
//Init
this.getWindowWidth()
})
}
}
</script>
<style scoped>
</style>
I was dealing with the same problem.
Do these steps:
Run your project (yarn start).
Open http://localhost:3000/ in Chrome.
In Chrome devtools clear site data in application tab.
Hard reload the page.

vue-carousel goToPage to programmatically change to selected page

I'm passing a collection of locations into vue-carousel. I'm using the same collection in a couple of other places on the page, emitting the selected location to the root, which is where the locations and selected location are stored, in an eventHub.
The tricky part was getting the carousel to move to the right page - I'm showing three locations at a time in larger viewports and just one on smaller, using the perPageCustom option. I create keys in the api in laravel and based on the size of the window, I'm moving to the right page and it all works, but when it loads I get an error because the ref doesn't exist when the watcher first fires off. I know that's the issue, but I'm not sure how to have a watcher for when the location changes, that doesn't watch when the page loads... perhaps using the mount?
My component:
<template>
<div>
<h3>Locations ({{locations.length}})</h3>
<p class="lead">Serving California in the greater Sacramento and Los Angeles areas.</p>
<carousel v-if="locations.length > 0" ref="locations-carousel" :scrollPerPage="true" :perPage="1" :perPageCustom="[[480, 1], [768, 3]]" v-on:pageChange="pageChange">
<slide v-for="loc in locations" :key="loc.id">
<div class="card" style="width: 18rem;" v-bind:class="{ closest: loc.is_closest, active: loc.id == location.id }">
<img v-on:click="changeLocation(loc.id)" v-if="loc.is_comingsoon === 0" class="card-img-top" :src="'/assets/images/location_'+loc.pathname+'.jpg'" alt="Card image cap">
<img v-on:click="changeLocation(loc.id)" v-if="loc.is_comingsoon === 1" class="card-img-top" :src="'/assets/images/coming-soon.png'" alt="Card image cap">
<div class="card-body">
<h5 class="card-title" v-on:click="changeLocation(loc.id)">{{ loc.name }}</h5>
<p class="card-text">{{ loc.address }}<br>{{ loc.city_name }}<br>{{ loc.phone | phone }}</p>
<div class="btn-group" role="group" aria-label="Location Buttons">
<a class="btn btn-outline btn-default" :href="'tel:'+ loc.phone"><font-awesome-icon icon="phone"></font-awesome-icon> call</a>
<a class="btn btn-outline btn-default" :href="loc.map"><font-awesome-icon icon="globe"></font-awesome-icon> map</a>
<a class="btn btn-outline btn-default" v-on:click="changeLocation(loc)" v-bind:class="{ active: loc.id == location.id }"><font-awesome-icon icon="star"></font-awesome-icon> pick</a>
</div>
<p class="card-text">{{ loc.note }}</p>
<span class="badge badge-closest" v-if="loc.is_closest"><font-awesome-icon icon="map-marker"></font-awesome-icon> closest detected</span>
<span class="badge badge-active" v-if="loc.id == location.id"><font-awesome-icon icon="star"></font-awesome-icon> selected <font-awesome-icon icon="angle-double-down" :style="{ color: 'white' }"></font-awesome-icon></span>
</div>
</div>
</slide>
</carousel>
<font-awesome-icon icon="spinner" size="lg" v-if="locations.length < 1"></font-awesome-icon>
</div>
</template>
<script>
Vue.filter('phone', function (phone) {
return phone.replace(/[^0-9]/g, '')
.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
});
import { Carousel, Slide } from 'vue-carousel';
var axios = require("axios");
export default {
name: 'locations-carousel',
props: ['location', 'pg', 'locations'],
components: {
Carousel,
Slide
},
data() {
return {
debounce: null,
subs: {},
clear: 0
};
},
watch: {
location: function(newVal, oldVal) { // watch it
console.log('Prop changed: ', newVal, ' | was: ', oldVal)
console.log('key: '+this.location.key);
if( window.innerWidth > 481 ) {
if( this.location.pg == 1 ) {
this.$refs['locations-carousel'].goToPage(-0);
} else {
this.$refs['locations-carousel'].goToPage(1);
}
} else {
this.$refs['locations-carousel'].goToPage(this.location.key);
}
}
},
methods: {
pageChange(i){
console.log('current Index', i);
},
changeLocation(location) {
this.$eventHub.$emit('location-loaded', location);
}
}
}
</script>
The error I'm getting:
[Vue warn]: Error in callback for watcher "location": "TypeError:
Cannot read property 'goToPage' of undefined"
found in
---> <LocationsCarousel> at resources/assets/js/components/LocationsCarousel.vue
<Root>
TypeError: Cannot read property 'goToPage' of undefined
at VueComponent.location (app.js?v=0.1:53288)
at Watcher.run (app.js?v=0.1:3937)
at flushSchedulerQueue (app.js?v=0.1:3685)
at Array.<anonymous> (app.js?v=0.1:2541)
at flushCallbacks (app.js?v=0.1:2462)
Perhaps you can check first to see if this.$refs['locations-carousel'] exists before accessing its properties/methods ..
watch: {
location: function(newVal, oldVal) { // watch it
console.log('Prop changed: ', newVal, ' | was: ', oldVal)
console.log('key: ' + this.location.key);
const locationsCarousel = this.$refs['locations-carousel']
if (window.innerWidth > 481) {
if (this.location.pg == 1) {
locationsCarousel && locationsCarousel.goToPage(-0);
} else {
locationsCarousel && locationsCarousel.goToPage(1);
}
} else {
locationsCarousel && locationsCarousel.goToPage(this.location.key);
}
}
},