Vue JS 3, Quasar 2 app- Keep alive not working - vue.js

I cant seem to get keep-alive working in a Quasar v2 (Vue v3) project.
I have seen other answered questions about this on SO and tried all of them that are Vue3 vintage.
Here are some of the various efforts in my App.vue
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</template>
based on other answers I have tried pretty much all combinations of substituting the below
<component :is="Component" :key="$route.fullPath"></component>
<component :is="Component" :key="$route.name"></component>
<keep-alive include="MyPageComponent">
MyPageComponent is a page component that contains a filterComponent with a datePicker and an listComponent that displays a list of filtered items.
What I am expecting to happen is I follow the route into MyPageComponent, change the filter date and the list items change.
Then I navigate away from the MyPageComponent and when I return the items and filterDate are as they were when I left.
Everything works in my project apart from the filterDate and list are not preserved between navigations.
Is this the correct expectation?
If so, what else could I look at? All the answers I have seen are fairly straightforward.
The only other thing I can think of is that when instantiated, MyPageComponent passes a hard coded starting date value to the filterComponent.

Related

How to move a Vue component around without loosing its state

I have a Vue3 wrapper component that implements a magnification feature in a dashboard. It displays an inner Vue component in two different ways. One is inline and the other is in a full-page pop-up for magnification. The gist of the template (I'm using Vuetify) is:
<template>
<v-card>
<!-- normal location -->
<component v-if="!full_page" :is="innerComponent" />
<!-- magnified full-page version -->
<v-dialog v-if="full_page">
<v-card>
<component :is="innerComponent" />
</v-card>
</v-dialog>
</v-card>
</template>
The above works in general, except that there are two different components in play. This means that if the non-magnified component has internal state then that is lost when switching to the magnified version. I see threee options:
guarantee that all state, even transient one, is maintained external to the component
reach into the component to clone state
ensure Vue moves the component from one spot in the DOM to the other
My question is whether the third option is possible?
With Vue 3 you can use Teleport component to move a component around.
You can do like that:
<div id="div1"></div>
<div id="div2"></div>
<Teleport :to="position ? '#div1' : '#div2'">
<YourComponent/>
</Teleport>
An important note is that
The teleport to target must be already in the DOM when the
component is mounted.
So you need some extra work to make it work with your own code.
Live demo

Add 404 page view outside <router-view> in Vue 3

I am working on a simple Vue-powered web app in which a list of projects is obtained as JSON from an API. I’m getting started with the Router and slots, and have gotten the following to work so far…
The app also features a header, and navigation menu. The navigation menu features links to the projects as retrieved from the API. Click on a project from the navigation menu send the user to website.com/projects/project1, the Vue Router matches website.com/projects/:slug. Based on matching the $route slug parameter, the project JSON is filtered and the currentProject is shown in the <router-view> section of the webpage (snippet from App.vue):
...
<router-view :currentProject="currentProject" v-slot="{ Component }">
<transition name="projectswitch" mode="out-in">
<component :is="Component" :key="$route.params.slug" />
</transition>
</router-view>
...
I would like to add a 404 page view, which does not include the header and navigation menu, when the user navigates to a non-existing route. I have made a simple template, PageNotFound.vue, that I would like to show as an independent page. Right now, it shows it inside the <router-view>, rather than rendering a whole new page, that includes only the template PageNotFound.vue.
How to handle this in terms of component architecture?
Thank you!

Pass props to v-dialog from parent to child in Vue

I'm new to Vue and have looked at some answers regarding my problem in which, I want to pass an id (for example 0099) from my child component to the parent via v-model. Is this possible, to pass an ID this way?
Here's my child code:
<template>
<v-dialog v-model="show" width="unset">
<v-card class="px-15 py-8" elevation="0">
<div class="px-6 py-8 mb-n4 text-center">
<span class="lucky-point--text text-h6">
Are you sure you want to access this employee?
</span>
</div>
</v-card>
</v-dialog>
</template>
What I want is that in v-model="show" I want to also include some id of an employee. Example v-model="show[0099] to the parent.
my parent code:
<ClaimDialog
:id="item.employeeid"
/>
although I used some props.
props: {
id: Number
}
Once I click from parent dialog it gets stacked on top of one another. I have found one answer but on my side its a bit tricky, since I'm new to Vue, and this approach is different from mine, since mine has a child component. Here's that question: Why are my dialogs stacked on top of one another? (Vuetify)
If you need to pass data from a child to a parent, then you must use $emit
Here is an example of a question and answer
Here is a link to the official documentation
If these links do not help you, then update the question: what event should the data be transmitted on, and how your components are connected (more code from your components)

Vue-js and different layouts

how would one layout the router-views, if you have, lets say 3 different layout to use for you app (e.g. layout for customers, layout for employer and admin-interface).
At the moment i implemented the customer "view" like:
<template>
<div id="app">
<HeaderBar/>
<Navigation></Navigation>
<router-view></router-view>
</div>
</template>
inside the App.vue file. I could use something like:
<div id="app">
<router-view name="header">
<HeaderBar/>
<Navigation></Navigation>
</router-view>
<router-view></router-view>
</div>
</template>
and load different headers for those "subroutes" but this seem's to be odd.
Also what, if i'd like to use an other index.html?
I'm using webpack for this app.
Or would you suggest to create different apps for this?
Many thanks
rene
You could try using dynamic components.
Basically you change which component is being rendered depending on your route.
So it would probably be something like this:
<component v-bind:is="headerComponent"></component>
and then your app can contain heeaderComponent property in data object that has a default value and gets changed when you click on a route that should use different header. Rinse and repeat for the footer.
As for the last question, I think you should only use one app. As it is possible to do and everything is still connected. I'm not sure but I don't know how would you, if need be, communicate between different instances of Vue.

Oddity with templates and root node with vue.js

I think this is possibly a bug I've stumbled across, not sure. I'm getting this Vue.js warning for a component:
vue.js:2611 [Vue warn]: Cannot use <template> as component root element because it may contain multiple nodes:
The problem seems to be this:
<template id="tpl-field">
<template v-if="fieldType==='checkbox-inline'">
<label class="checkbox-inline">[SNIP]</label>
</template>
<template v-else>
[SNIP]
</template>
</template>
So I have two template nodes, which seems to be the multiple nodes it's choking on (certainly each of the template nodes contains just a single node). Yet this is an if-else in Vue - if one of the nodes is present, the other logically cannot be.
Demo of the problem here: https://jsfiddle.net/jonmor51/Ldz3k0jp/1/. If I wrap everything in a div, it works. But without, it fails. (Unfortunately, in the context where I want to use this, namely for inline checkboxes within a Bootstrap grid, wrapping in a div breaks things).
Not sure if this will solve your problem with bootstrap... but you could wrap you inner templates with a <transition> tag and set a key to each one.
Please check this working fiddle
https://jsfiddle.net/AldoRomo88/7c7znu3p/
helpful thing - just use div display: contents as a root of the component and browser will ignore that element and consider child elements (which can be many) as children of upper dom element
<div style="display: contents">
<template v-if="...">
<template v-for="..."> ...
</template>
<template v-if="...">
</template>
</div
works even inside tables!
The inner templates direct children, are they single elements? If so, you can just remove the inner templates and move v-if to the label.
Or, just use span rather than div as your quick fix, which won't break inline elements' style.