V-img destroys my router and links stop to work - vuejs3

I use Vuejs3 (incl. Vue router) with Vuetify 3.0.0-beta.10
I built 4 different simple pages (Home.vue / HowItWorks.vue / Login.vue / Register.vue)
On the Home.vue page is a image implemented via v-img
I route between the different pages via named routes
I face the following problem. I can route between the different pages without any problem but as soon as I click on my home-link in my navbar to get to my Home.vue page, I get the following error and the routing doesn't work anymore. I can still see that the URL changes when I click a link but the side os not displayed. I figured out that as soon as I delete the image (implemented via v-img) in my Hone.vue file, the problem disappears.
What do I do wrong?
Error Message
Uncaught (in promise) TypeError: oldBindings[i] is undefined
invokeDirectiveHook runtime-core.esm-bundler.js:2779
patchElement runtime-core.esm-bundler.js:5349
flushPostFlushCbs runtime-core.esm-bundler.js:339
flushJobs runtime-core.esm-bundler.js:393
promise callback*queueFlush runtime-core.esm-bundler.js:280
queueJob runtime-core.esm-bundler.js:274
scheduler runtime-core.esm-bundler.js:1803
triggerEffect reactivity.esm-bundler.js:394
triggerEffects reactivity.esm-bundler.js:384
triggerRefValue reactivity.esm-bundler.js:1000
effect reactivity.esm-bundler.js:1134
triggerEffect reactivity.esm-bundler.js:394
triggerEffects reactivity.esm-bundler.js:379
triggerRefValue reactivity.esm-bundler.js:1000
set value reactivity.esm-bundler.js:1045
poll VImg.tsx:166
pollForSize VImg.tsx:176
init VImg.tsx:136
promise callback*nextTick runtime-core.esm-bundler.js:242
init VImg.tsx:126
observer index.ts:54
mounted index.ts:33
callWithErrorHandling runtime-core.esm-bundler.js:155
callWithAsyncErrorHandling runtime-core.esm-bundler.js:164
invokeDirectiveHook runtime-core.esm-bundler.js:2786
mountElement runtime-core.esm-bundler.js:5222
flushPostFlushCbs runtime-core.esm-bundler.js:339
flushJobs runtime-core.esm-bundler.js:393
runtime-core.esm-bundler.js:2779:12
invokeDirectiveHook runtime-core.esm-bundler.js:2779
patchElement runtime-core.esm-bundler.js:5349
flushPostFlushCbs runtime-core.esm-bundler.js:339
flushJobs runtime-core.esm-bundler.js:393
(Async: promise callback)
queueFlush runtime-core.esm-bundler.js:280
queueJob runtime-core.esm-bundler.js:274
scheduler runtime-core.esm-bundler.js:1803
triggerEffect reactivity.esm-bundler.js:394
triggerEffects reactivity.esm-bundler.js:384
triggerRefValue reactivity.esm-bundler.js:1000
effect reactivity.esm-bundler.js:1134
triggerEffect reactivity.esm-bundler.js:394
triggerEffects reactivity.esm-bundler.js:379
triggerRefValue reactivity.esm-bundler.js:1000
set value reactivity.esm-bundler.js:1045
poll VImg.tsx:166
pollForSize VImg.tsx:176
init VImg.tsx:136
(Async: promise callback)
nextTick runtime-core.esm-bundler.js:242
init VImg.tsx:126
observer index.ts:54
(Async: IntersectionCallback)
mounted index.ts:33
callWithErrorHandling runtime-core.esm-bundler.js:155
callWithAsyncErrorHandling runtime-core.esm-bundler.js:164
invokeDirectiveHook runtime-core.esm-bundler.js:2786
mountElement runtime-core.esm-bundler.js:5222
flushPostFlushCbs runtime-core.esm-bundler.js:339
flushJobs runtime-core.esm-bundler.js:393
Home.vue file (When i delete the v-img here, the problem disappears)
<template>
<div>
<v-app-bar
elevation="10"
color="white"
>
<router-link :to="{ name: 'Home'}">
<img
class="ml-2"
:src="logoImage"
alt="logo"
height="40"
>
</router-link>
<v-spacer></v-spacer>
<router-link :to="{ name: 'HowItWorks'}">
<h4 class="font-weight-light mx-5 text-black">
{{ $t('nav.howitworks') }}
</h4>
</router-link>
<router-link :to="{ name: 'Login'}">
<h4 class="mx-5">
<v-btn
color="black"
class="font-weight-black"
variant="outlined"
>
{{ $t('nav.login') }}
</v-btn>
</h4>
</router-link>
</v-app-bar>
</div>
</template>
<script setup>
import logoImage from '#/assets/pics/postvivo_logo_black.png'
</script>
<style scoped>
a { text-decoration: none; }
</style>
Thanks for your help!!
Chris

Related

[Vue warn]: Property "xxx" was accessed during render but is not defined on instance

I'm getting this super confusing Vue warning and I can't figure it out:
[Vue warn]: Property "me" was accessed during render but is not defined on instance.
at <UserReputation user= {reputation: {…}, _id: '638f81dbb288267e6340ddbc', username: 'artsborba'…} class="mt-1" >
...
Here on StackOverflow I can find more topics with this warning, but seems each one is a different case, and mine is just not making sense! My vue version is ^3.1.0, vuetify ^3.1.0 and vite ^2.5.4.
My component looks like:
// MyComponent.vue
<v-menu location="end" location-strategy="connected">
<template #activator="{ props }">
<div
v-bind="props"
class="user-info-container cursor-pointer"
>
<UserAvatar
:user="me"
/>
<div v-if="me" class="user-data">
<div class="username-row">
{{ me.username }}
<AppIcon
icon="downward-arrow"
color="primary"
class="user-menu-icon"
:class="{ 'is-active': props['aria-expanded'] === 'true' }"
/>
</div>
<!-- HERE WE HAVE THE WARNING SOURCE -->
<UserReputation :user="me" class="mt-1" />
</div>
</div>
</template>
...
</v-menu>
In the same component I have the me set as a prop:
props: {
me: {
validator: prop => typeof prop === 'object' || prop === null,
required: true
}
},
Now, please notice that in the same component I have another one using this me pro (<UserAvatar :user="me"...>), which doesn't trigger this warning. Only the <UserReputation... component usage does! If I comment out the <UserReputation... tag, the warning goes away.
I already tried placing this me as a computed value instead of a prop, directly inside MyComponent.vue (it comes from a Pinia store) and many other structures with no success. Hopefuly someone can help on this! Thanks in advance.
Maybe you are accesing at me property inside your UserReputation component, but in the parent you are passing me to user prop, like this :user="me", so... you need to access to user prop instead me prop inside UserReputation component.
If this answer doesn't resolve the question, please share us the structure of UserReputation component.

TypeError: can't access property "nodeValue", node is null

In vue3 component I have this code:
<script>
export default {
data() {
return {
vendedores: [{
id: 1,
nombre: "Name test1"
}],
};
}
};
</script>
Having this template, there everything works fine:
<div v-for="vendedor in vendedores"
:key="vendedor.id">
</div>
But in this one is displaying an error everytime vite compiles the assets:
<div v-for="vendedor in vendedores"
:key="vendedor.id">
<button
:class="(vendedor.seleccionado)? 'bg-zinc-800 border-amber-300' : 'bg-transparent'"
class="border-zinc-400 rounded-full py-3 text-left hover:border-violet-200"
>
<span> Test</span>
</button>
</div>
The error displayed in the console is the following:
TypeError: can't access property "nodeValue", node is null
setText runtime-dom.esm-bundler.js:30
processText runtime-core.esm-bundler.js:5109
patch runtime-core.esm-bundler.js:5064
patchKeyedChildren runtime-core.esm-bundler.js:5849
patchChildren runtime-core.esm-bundler.js:5792
patchElement runtime-core.esm-bundler.js:5305
processElement runtime-core.esm-bundler.js:5165
patch runtime-core.esm-bundler.js:5082
...
I have updated #vite to last version (^3.2.0) and vue3 (3.2.41). Other components working fine in other projects with the same version.

Vue - requests and watch data on unmounted components

I'm new to vue and strugling with some props and attributes.
I have a vue application where the main app is calling three different components:
Navbar,
Sidebar
MapContainer
In Navbar user will fill a selector with information about city and states. After user presses search, the list of results will then show up in the Sidebar menu.
Sidebar itself is a simple component carrying only a router-view for it's children components which are Results and Details
Results will receive the result of the search performed in the Navbar component. When user clicks any item in the Results component, Sidebar will then load Details taking the place of Results with detailed information about that place.
the problem is that the data used to make the request(city and states) comes from the first component navbar. I'm passing this data to sub-components using vue-router params option. When component Results gets unmounted, I lost all the data that was passed, even adding a Watch couldn'd fix the problem and thus can't return back to the previous page. Even adding a Watch couldn'd fix the problem. What's the proper way to handle data across components that area unmounted?
Navbar.vue
<template>
<div class="navbar">
<div class="logo">
Logo
</div>
<div class="middle">
<div class="flex-selectors">
<div class="navbar-options">
<select v-model="state_id" class="main-selectors" #click="load_cities">
<option v-for="state in states" :value="state.state_id" :key="state">
{{ state.state }}
</option>
</select>
<select v-model="city_id" class="main-selectors">
<option v-for="city in cities" :value="city.city_id" :key="city">
{{ city.city }}
</option>
</select>
</div>
<div class="search">
<button #click="seach">
<router-link :to="{name: 'results', params: {state: state_id, city: city_id} }" aria-current="page" title="Resultados">
<div>Search</div>
</router-link>
</button>
</div>
</div>
</div>
</template>
Sidebar.vue
<template>
<div class="sidebar">
<router-view></router-view>
</div>
</template>
Results.vue
<template>
<div v-if="areas.length">
<router-link :to="{name: 'details' }" tag="div" class="container" #click="load(area)" v-for="area in areas" :key="area" :value="area">
<!-- BUNCH OF DIVS AND V-FOR -->
</router-link>
</div>
<div v-else>
NA
</div>
</template>
<script>
export default {
data() {
return {
state_id: this.$route.params.state,
city_id: this.$route.params.city,
areas: [],
}
},
methods: {
search(state_id, city_id) {
load_areas.get(state_id, city_id).then(
result => {
this.areas = result.data
}
)
}
},
mounted() {
this.emitter = inject('emitter')
this.searchAreas(this.state_id, this.city_id)
},
created() {
this.$watch(
() => this.$route.params,
(toParams, previousParams) => {
this.searchAreas(toParams.state, toParams.city)
}
)
},
watch: {}
}
</script>
What's the proper way to handle data across components that are
unmounted?
You cannot access data from an unmounted component.
When multiple components need to access or modify the same data, a good option to look into is state management. Pinia is the new official library recommendation for state management.
Instead of passing data through vue-router params, create a store for it. Set results of your search query from Navbar component and access it in Results component. When Results component gets unmounted, you won't lose the data.

Updating parent of recursive component in Vue

I've made a menu showing systems and their subsystems (can in theory be indefinitely) using a recursive component. A user can both add and delete systems, and the menu should therefore update accordingly.
The menu is constructed using a "tree"-object. This tree is therefore updated when a new system is added, or one deleted. But, I now have a problem; even though the new child component is added when the tree is rerendered, the classes of it's parent-component doesn't update. It is necessary to update this because it defines the menu-element to having children/subsystems, and therefore showing them.
Therefore, when adding a new subsystem, this is presented to the user:
<div class="">
<a href="#/Admin/364" class="item">
<i class=""></i>Testname
<div class=""></div>
</a>
</div>
Instead of this:
<div class="menu transition visible" style="display: block !important;">
<a href="#/Admin/364" class="item">
<i class=""></i>Testname
<div class=""></div>
</a>
</div>
It works fine adding a subsystem to a system which already have subsystems (since the menu-class is already present), but not when a subsystem is added to one without subsystems. In that case, the menu ends up looking like this:
The "opposite" problem also occurs on deletion, since the parent still has the menu-class:
Here's the code for the recursive component:
<template>
<router-link :to="{ name: 'Admin', params: { systemId: id } }" class="item" >
<i :class="{ dropdown: hasChildren, icon: hasChildren }"></i>{{name}}
<div :class="{ menu: hasChildren }">
<systems-menu-sub-menu v-for="child in children" :children="child.children" :name="child.name" :id="child.id" :key="child.id"/>
</div>
</router-link>
</template>
<script type = "text/javascript" >
export default {
props: ['name', 'children', 'id'],
name: 'SystemsMenuSubMenu',
data () {
return {
hasChildren: (this.children.length > 0)
}
}
}
</script>
I'm guessing this has to do with Vue trying to be efficient, and therefore not rerendering everything. Is there therefore any way to force a rerender, or is there any other workaround?
EDIT: JSFiddle https://jsfiddle.net/f6s5qzba/

VueJS component won't render on front end (possibly Drupal issue)

The site I'm currently working on is built in Drupal 7. I have one form that requires user input so I'm attempting to build it with VueJS. The form is contained all within one template file (.tpl.php) and all the content is provided in this template file or via the VueJS Javascript (nothing is coming from the CMS).
The issue I have is that the Vue components are not rendering on the front-end, but when I copy the code into a JSFiddle they do, so I'm guessing it is an issue with the interaction between VueJS and Drupal. Here is a screenshot of my markup when inspecting...
Here is the code from the .tpl.php file...
<div id="app">
<form>
<div>
<label for="year">Per Year</label>
<input type="radio" name="frequency" id="year" value="year" v-model="frequency" checked>
<label for="month">Per Month</label>
<input type="radio" name="frequency" id="month" value="month" v-model="frequency">
</div>
</form>
<ul class="plans">
<template id="plan-component">
<h2 class="plan-name">{{ name }}</h2>
<h2 class="plan-cost">{{ price }}</h2>
<h2 class="plan-tagline">{{ tagline }}</h2>
Choose this plan
</template>
<li>
<plan-component :frequency="frequency"
name="Basic"
tagline="Basic tagline"
price-yearly="Free"
price-monthly="Free"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Rec"
tagline="Rec tagline"
price-yearly="3"
price-monthly="4"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Team"
tagline="Team tagline"
price-yearly="4"
price-monthly="5"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Club"
tagline="Club tagline"
price-yearly="5"
price-monthly="6"
></plan-component>
</li>
</ul>
</div>
..and the code from my JS file...
Vue.component('plan-component', {
template: '#plan-component',
props: ['frequency', 'name', 'tagline', 'priceYearly', 'priceMonthly'],
computed: {
'price': function() {
if (this.frequency === 'year') {
return this.priceYearly;
} else {
return this.priceMonthly;
}
}
},
methods: {
makeActivePlan() {
// We dispatch an event setting this to become the active plan
this.$dispatch('set-active-plan', this);
}
}
});
new Vue({
el: '#app',
data: {
frequency: 'year',
activePlan: {name: 'no', price: 'You must select a plan!' }
},
events: {
'set-active-plan': function(plan) {
this.activePlan = plan;
}
},
});
And here is the JSFiddle which outputs the components correctly - https://jsfiddle.net/2xgrpLm6/
What browser are you using? <template> tags are not supported in IE.
Another idea is to make sure you are never using fragment components (meaning wrap everything inside your template with a div like so:
<template id="foobar">
<div>
CONTENT HERE
</div>
</template>
Lastly, have you turned on Vue debug mode? Before you instantiate your Vue instance, set Vue.config.debug = true and see if you get console errors then.
Try moving the <template id="plan-component">...</template> code outside of the Vue instance. I.e., such that it is not contained within <div id="app">...</div>.
This has solved a similar problem for me in the past, though I'm not sure if it applies here.
For anyone having a similar issue, the solution was simple. After Jeff suggested turning on Vue debug mode (and downloading the Dev version of Vue JS instead of minified - https://vuejs.org/guide/installation.html) the console gave the error [Vue warn]: Cannot find element: #app.
The issue was that Drupal was loading my scripts in the <head>, before <div id="app"> was loaded in the DOM. As such #app couldn't be found. After outputting the scripts before the closing <body> tag all was sorted. See here for more information [Vue warn]: Cannot find element

Resources