Netlify build causes reading from undefined error vuejs - vue.js

I am trying to develop an application in vuejs and deploy it using netlify. Note that I am very new to vuejs. I have no warnings or errors in production but when deploying, the website is blank and the following error appears in console :
TypeError: Cannot read properties of undefined (reading 'currentPath')
at index.7d385d0f.js:54:2330
at ls (index.7d385d0f.js:1:23187)
at Proxy.<anonymous> (index.7d385d0f.js:54:2247)
at vn (index.7d385d0f.js:1:15170)
at Jn.b [as fn] (index.7d385d0f.js:1:38048)
at Jn.run (index.7d385d0f.js:1:4525)
at G.c.update (index.7d385d0f.js:1:38314)
at G (index.7d385d0f.js:1:38340)
at rt (index.7d385d0f.js:1:37206)
at ve (index.7d385d0f.js:1:37000)
I only use "currentPath" in one file :
In the <script> tag :
export default {
data: {
currentPath: "",
},
data() {
return {
currentPath: window.location.hash || "",
};
},
computed: {
currentView() {
return routes[this.currentPath.slice(1) || "/"].route || NotFound;
},
},
mounted() {
window.addEventListener("hashchange", () => {
this.currentPath = window.location.hash || "";
});
},
};
In my html :
<template>
<notifications />
<header class="header">
<a
v-for="(route, url) in routes"
:key="route.name"
class="header-item"
:class="{ 'header-item-current': this.currentPath === `#${url}` }"
:href="`#${url}`"
>
{{ route.name }}
</a>
</header>
<component class="content" :is="currentView" />
</template>

Okay it would seem it is not necessary (and even causes problems) to use 'this.' inside the html of a vuejs SFC.
I have changed
<a
v-for="(route, url) in routes"
:key="route.name"
class="header-item"
:class="{ 'header-item-current': this.currentPath === `#${url}` }"
:href="`#${url}`"
>
{{ route.name }}
</a>
to
<a
v-for="(route, url) in routes"
:key="route.name"
class="header-item"
:class="{ 'header-item-current': currentPath === `#${url}` }"
:href="`#${url}`"
>
{{ route.name }}
</a>
and not only has the error gone away but everything works fine !

Related

Vue-multiselect prevent selecting any items when using Single select (object)

I'm using Vue-multiselect 2.1.4
It works like a charm when I use single select with array options. But in case of using single select with array of objects, all items are green and they are not selectable! (They have "is-selected" class)
To clarify the problem, I used the sample code from the project website and replace the options with my data.
<multiselect v-model="value" deselect-label="Can't remove this value"
track-by="name" label="name" placeholder="Select one"
:options="options" :searchable="false" :allow-empty="false">
<template slot="singleLabel" slot-scope="{ option }">
<strong>{{ option.name }}</strong> is written in
<strong> {{ option.language }}</strong>
</template>
</multiselect>
const config = {
data() {
return {
value: null,
options: []
}
},
async mounted() {
await this.getTerminals();
},
methods: {
async getTerminals() {
await window.axios.get("/api/Operation/GetTerminals")
.then(resp => {
this.$data.options = resp.data;
})
.catch(err => {
console.error(err);
});
},
}
};
const app = Vue.createApp(config);
app.component('Multiselect', VueformMultiselect);
app.mount('#app');
In case of array of objects, first you need to populate the values in object and then push the object in options array. And there will be few changes in the template as well. For example if your object is like this, following will work:
data(){
return{
value: null,
option: {
value: "",
name: "",
icon: "",
},
options: [],
}
},
methods: {
getData(){
//call your service here
response.data.list.forEach((item, index) => {
self.option.value = item.first_name + item.last_name;
self.option.name = item.first_name + " " + item.last_name;
self.option.icon =
typeof item.avatar !== "undefined" && item.avatar != null
? item.avatar
: this.$assetPath + "images/userpic-placeholder.svg";
self.options.push({ ...self.option });
});
}
}
Then in the template fill the options like this:
<Multiselect
v-model="value"
deselect-label="Can't remove this value"
track-by="value"
label="name"
:options="options"
:searchable="false"
:allow-empty="false"
>
<template v-slot:singlelabel="{ value }">
<div class="multiselect-single-label">
<img class="character-label-icon" :src="value.icon" />
{{ value.name }}
</div>
</template>
<template v-slot:option="{ option }">
<img class="character-option-icon" :src="option.icon" />
{{ option.name }}
</template>
</Multiselect>
Call your getData() function in created hook.
For me the solution was to use the "name" and "value" keys for my object. Anything else and it doesn't work (even if they use different keys in the documenation). This seems like a bug, but that was the only change I needed to make.

Including text when an image/icon is shown

At the moment I am trying to include different text when an image and/or icon shows on the page. Here is the code for the vue file:
<template>
<div class="profile">
<div
:class="{
'flags--relevant': hasFlagType('medication'),
'flags--active': flag == 'medication'
}"
class="flags"
#click="setFlag('medication')"
>
<medication-icon
:class="[
hasFlagType('medication')
? 'medication-icon--focus'
: 'medication-icon--blur',
]"
/>
</div>
<div
:class="{
'flags--relevant': hasFlagType('condition'),
'flags--active': flag == 'condition'
}"
class="flags"
#click="setFlag('condition')"
>
<treatment-icon
:class="[
hasFlagType('condition')
? 'treatment-icon--focus'
: 'treatment-icon--blur',
]"
/>
</div>
<div
:class="{
'flags--relevant': hasFlagType('translator'),
'flags--active': flag == 'translator',
}"
class="flags"
#click="setFlag('translator')"
>
<foreign-dialect-icon
:class="[
hasFlagType('translator')
? 'foreign-dialect-icon--focus'
: 'foreign-dialect-icon--blur',
]"
/>
</div>
</div>
</template>
<script>
export default {
components: {
ForeignDialectIcon,
MedicationIcon,
TreatmentIcon,
},
props: {
userFlags: {
type: Array,
default() {
return {};
},
},
},
data() {
return {
flags: this.userFlags,
flag: null,
title: "Requires daily medication",
title2: "Specialist health condition",
title3: "Requires a translator",
};
},
methods: {
hasFlagType(flagType) {
return this.flags[flagType] !== undefined;
},
setFlag(flagType) {
if (this.hasFlagType(flagType)) {
this.flag = flagType;
}
},
resetFlag() {
this.flag = null;
},
},
};
</script>
I have tried outputting the titles in the data section for each icon and they still show even if the icon doesn't show. I need it to output the title when the image is shown and the many attempts I've tried haven't worked so was wondering how I am able to solve this?
Assuming the title should only appear when the corresponding icon is focused, you could use the same condition (hasFlagType(...)) with v-if to render the title:
<div>
<medication-icon .../>
<span v-if="hasFlagType('medication')">{{ title }}</span>
</div>
<div>
<treatment-icon .../>
<span v-if="hasFlagType('condition')">{{ title2 }}</span>
</div>
<div>
<foreign-dialect-icon .../>
<span v-if="hasFlagType('translator')">{{ title3 }}</span>
</div>

Vue - Unable to use variable in template

I have this code in my VUE file:
<template>
<div class="row">
<div class="col-12">
<section class="list">
<draggable class="drag-area" :list="picsNew" :options="{animation:200, group:'status'}" :element="'article'" #add="onAdd($event, false)" #change="update">
<article class="card" v-for="(photo, index) in picsNew" :key="photo.id" :data-id="photo.id">
<header>
{{ this.galCode }}{{ photo.filename }}
</header>
</article>
</draggable>
</section>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: {
draggable
},
props: ['myPics', 'galId', 'phCode', 'galCode'],
data() {
return {
picsNew: this.myPics,
}
},
methods: {
update() {
this.picsNew.map((photo, index) => {
photo.order = index + 1;
});
let photos = this.picsNew;
console.log(this.galCode)
axios.put('/gallery/' + this.galId + '/updateAll', {
photos: photos
}).then((response) => {
console.log(response.data);
}).catch((error) => {
console.log(error);
})
}
}
}
</script>
in the template, photo.filename works, but this.galCode throws these two errors:
app.js:44152 [Vue warn]: Error in render: "TypeError: Cannot read property 'galCode' of undefined"
found in
---> <DraggablePic> at resources/js/components/draggablepic.vue
app.js:45415 TypeError: Cannot read property 'galCode' of undefined
The variable contains a value, as i am printing it to console. What am I doing wrong?
The problem is that you try to access props variable directly from your template. To solve this, initalize a state variable (under data {}) Within props value as default like you did With picsNeW.
another remark, avoid to use "this" from template, you should access directly datas form its name. Use default value in your props, this is recommended :)
The line {{ this.galCode }}{{ photo.filename }} should be {{ galCode }}{{ photo.filename }}. Your problem is the this you added
First you should define Default value as :
props: {
name: {
type: String,
default: 'default'
},
...
galCode: {
type: Number,
default: 0
},
},
Second be sure you receive desired data, specially in nested object you should check the object defined to prevent receive undefined property error, like use v-if :
<header>
<template v-if="galCode">{{ galCode }}</template> // can use v-else here too print default value
<template v-if="photo.filename"> {{ photo.filename }}</template>
</header>

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);
}
}
},

Vue: data from grandparent to grandchild (search component)

In my Vue app I have a view ('projects.vue') that gets some .json and which has a child component ('subheader.vue') which imports a search/filter mixin. I had this working but I wanted to split out the search elements from the subheader component to its own component, so subheader would hold only the headings and then import the search component. Despite adapting the props and bindings from the working version, my new three-component setup is throwing an error. Here's the setup:
the searchMixin.js:
export default {
computed: {
filteredProjects: function() {
const searchTerm = this.search.toLowerCase();
if (!searchTerm) {
return false;
}
return this.projects.filter((project) => {
return (project.client.toLowerCase().match(searchTerm)) ||
(project.contacts.filter((el) => {
return el.name.toLowerCase().match(searchTerm);
}).length > 0) ||
(project.projectReference.toLowerCase().match(searchTerm));
});
}
}
}
Projects.vue:
<template>
<div class="container" id="projects">
<!-- app-subheader is global component, imported & registered in main.js -->
<app-subheader v-bind:title="title" v-bind:subtitle="subtitle" />
[ snip irrelevant stuff ]
</div>
</template>
<script>
export default {
data () {
return {
title: "Projects",
subtitle: "",
projects: []
}
},
created: function() {
this.$http.get('https://xyz.firebaseio.com/projects.json')
.then(function(data){
return data.json();
})
.then(function(data){
var projectsArray = [];
for (let key in data) {
data[key].id = key;
this.projectID = key;
projectsArray.push(data[key]);
}
this.projects = projectsArray;
})
},
} // export default
</script>
subheader.vue:
<template>
<div class="subheader">
<div class="headings">
<h1 v-html="title"></h1>
<h2 v-html="subtitle"></h2>
<!-- I want to conditionally include <app-search /> according to an ID on an element in the grandparent (e.g., projects.vue) -->
<app-search v-bind:projects="projects" />
</div>
</div>
</template>
<script>
import Search from './search.vue';
export default {
components: {
'app-search': Search
},
props: [ "title", "subtitle", "projects" ],
data() {
return {
search: "",
projects: []
}
},
created: function() {
console.log("created; log projects", this.projects);
},
methods: {},
computed: {}
}
</script>
search.vue:
<template>
<div class="search-wrapper">
<div class="search">
<input type="text" v-model="search" placeholder="search by client, contact name, description, project, source" />
</div>
<div class="search-results-wrapper">
<h3>search-results:</h3>
<span class="results-count" v-if="filteredProjects.length == 0">
no results matching search "{{ search }}":
</span>
<span class="results-count" v-if="filteredProjects.length > 0">
{{ filteredProjects.length }} result<span v-if="filteredProjects.length > 1">s</span> matching search "{{ search }}":
</span>
<ul class="search-results" v-bind:class="{ open: filteredProjects.length > 0 }">
<li v-for="(project, ix) in filteredProjects" :key="ix">
{{ ix + 1 }}:
<router-link v-bind:to="'/project-detail/' + project.id">
{{ project.client }} ({{ project.projectReference }})
</router-link>
</li>
</ul>
</div>
</div><!-- END .search-wrapper -->
</template>
<script>
import searchMixin from '../mixins/searchMixin.js';
export default {
props: [ "projects" ],
data() {
return {
search: "",
}
},
created: function() {
},
mixins: [ searchMixin ],
}
When the search function is invoked, this error is thrown:
[Vue warn]: Error in render: "TypeError: Cannot read property 'filter' of undefined"
found in --->
<AppSearch> at src/components/search.vue
<AppSubheader> at src/components/subheader.vue
<Projects> at src/components/projects.vue
<App> at src/App.vue
... which seems to suggest the search mixin is not getting 'projects'.
Also, in subheader.vue, I get various errors whether I have 'projects' as a prop or 'projects: []' as a data key, and in once case or another I either get no results from the search function or an error, "Property or method "projects" is not defined on the instance but referenced during render".
Obviously I'm lacking clarity on the docs re; grandparent-parent-child data flow. Any help is greatly appreciated.
Whiskey T.