Vue 3 - component SSR not support - vue.js

if (process.isClient) {
app.use(require('v-calendar'), {})
}
<client-only>
<v-calendar />
<v-date-picker v-model="date" />
</client-only>
[Vue warn]: Failed to resolve component: v-calendar

Related

Display a specific route in a different router-view

I've got a Vue 3 app with Vue Router 4 and I want to achieve this:
<template>
<v-app>
<router-view></router-view> //This is where login would be
<app-layout>
<router-view /> //Everything else
</app-layout>
</v-app>
</template>
<script lang="ts" setup>
import AppLayout from "./components/AppLayout.vue";
</script>
I've got an <app-layout> component which includes navbar and a sidebar, but I don't want to display those when the user is not logged in. I also don't want to wrap each component in <app-layout> individually.
Is there a way I can achieve this?
You can use the Vue-router's v-slot API like this :
<template>
<v-app>
<router-view v-slot="{ Component, route }">
<component v-if="route.name === 'Login'" :is="Component" />
<app-layout v-else>
<component :is="Component" />
</app-layout>
</router-view>
<!-- Or -->
<router-view v-slot="{ Component, route }">
<component :is="route.name === 'Login' ? 'template' : 'app-layout'">
<component :is="Component" />
</component>
</router-view>
</v-app>
</template>
<script lang="ts" setup>
import AppLayout from "./components/AppLayout.vue";
</script>
And in your router, for the login route, don't forget to add the route name :
{
name: 'Login', // important
// ...
}

can you pass router-view as a prop in vuejs

Is it possible to pass as a prop when calling another component?
Essentially, I have components, and views, I build my views using various components. I want to have 1 styled component which I can reuse, so I was thinking to have a WebsiteLayout.vue:
<template>
<a-layout-content :style="{ padding: '0 24px', minHeight: '280px' }" />
{{ content }}
</template>
<script>
export default {
name: "View",
components: {
},
props: ["content"],
};
</script>
And in my App.vue:
<template>
<Content content=<router-view /> />
</template>
This isnt correct, but wondering if something like this is possible, and how I could achieve it?
With Vue 3 and Router 4, you can do something like
<router-view v-slot="{ Component }">
<SomeComponent>
<component :is="Component" />
</SomeComponent>
</router-view>
and then
//SomeComponent.js
<template>
<div class="wrapper">
<slot></slot>
</div>
</template>
here is an example with transition component as a wrapper for the router-view component
to know more about scoped slots you can see this

Vue3 router + transitions warnings

I have a wrapper component with a transition:
// Wrapper.vue
<template>
<transition
appear
mode="out-in"
enter-active-class="animate__animated animate__fadeIn animate__faster"
leave-active-class="animate__animated animate__fadeOut animate__faster"
>
<div :key="$route.path">
<slot />
</div>
</transition>
</template>
Then, I populate the default slot with some component from router as follows:
// Page.vue
<template>
<Wrapper>
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</Wrapper>
</template
And I'm getting
[Vue Router warn]: <router-view> can no longer be used directly inside <transition> or <keep-alive>. warnings, which seems weird since I'm using the correct syntax imho. Is this intended and if so, what am I missing?
Note: It works properly, I just don't like looking at warnings :)
EDIT: A bit more context - I'm trying to create wrappers for desktop and mobile devices while desktop devices should have the transition described above. The mobile device wrapper is done quite differently and is not relevant here.
The warning is not supposed to display in this scenario, but only when the "router-view" is the direct child of a "transition" or "keep-alive" component.
The bug has been reported here: https://github.com/vuejs/router/issues/1306
By official guide you should use <transition> or <keep-alive> inside <RouterView /> and vice-versa not applicable.
<router-view v-slot="{ Component, route }">
<transition name="fade">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
<router-view> exposes a v-slot API mainly to wrap your route components with <transition>, <keep-alive> components.
update:
A computed property may be helpful for this scenario. Tough, I don't know how you've implemented code for small devices. This is one way of doing...
<script>
function isSmallDevice() {
/*
code for checking
device resolution
*/
return <Boolean>
}
export default {
computed: {
setTransitionProperty: function () {
return isSmallDevice ? '' : 'fade'
}
}
}
</script>
<router-view v-slot="{ Component, route }">
<transition :name="setTransitionProperty" mode="out-in">
<template #default>
<component
:is="Component"
:key="route.meta.usePathKey ? route.path : undefined"
/>
</template>
<template #fallback> Loading... </template>
</transition>
</router-view>
Another way may be conditional rendering, using v-if, and v-else directives.

[Vue warn]: Failed to resolve component:

I just tried to make a single login form in Vue but it returns
[Vue warn]: Failed to resolve component: v-text-field
and
[Vue warn]: Failed to resolve component: v-form
the code in login component:
<template lang="html">
<div>
<v-form>
<v-text-field v-model="loginInfo.username" label="Username"/>
<v-text-field v-model="loginInfo.password" label="Password"/>
<v-btn>Login</v-btn>
</v-form>
</div>
</template>
<script>
export default {
data() {
return{
loginInfo: {
username:'',
password:'',
}
}
},
}
</script>
I got the same issue and put around 2 hours to figure out. The only problem with me was my browser was getting the cached js file that did not have my required component.
I see two options to answer the question:
Either you use Vuetify.js as you are trying to in the code provided above. I would recommend checking if you are using Vuetify.js correctly by following the quick start guide.
The other option would be not to use Vuetify.js and therefor use the regular HTML expressions in the form:
<div>
<form>
<label for="username">Username</label>
<input id="username" type="text" v-model="loginInfo.username"/>
<label for="password">Password</Label>
<input id="password" type="password" v-model="loginInfo.password"/>
<input type="submit"value="Login" />
</form>
</div>

[Vue warn]: Error in render: "TypeError: _vm.selectedProductDetails is null"

I have strange problem with render my components.
<app-content-switcher :state="!!selectedProductDetails">
<template slot="up">
<product-d-p :product-id="selectedProductDetails.id">
<template slot-scope="{data: product, loading, error}">
<label v-if="loading">Loading</label>
<div v-else-if="product">
{{product}}
</div>
<label v-else-if="error">Error</label>
</template>
</product-d-p>
</template>
<template slot="down">
Nope
</template>
</app-content-switcher>
AppContentSwitcher is very simple.
<template>
<div>
<slot
name="up"
v-if="state"
/>
<slot
name="down"
v-else
/>
</div>
</template>
<script>
export default {
name: "AppContentSwitcher",
props: {
state: {
type: Boolean,
required: true
}
}
}
</script>
The problem is selectedProductDetails.id where selectedProductDetails is null.
I don't render this component if selectedProductDetails is null, two lines higher I set state in 'AppContentSwitcher', which shouldn't render this component.
What is wrong here? How to fix it?
I find workaround. I created method:
getSelectedProductDetailsId: function (){
return this.selectedProductDetails?.id
}
and it work :)
Still I don't understand why my first solution doesn't work.