Vuetify - How to loop through multiple custom components in a carousel - vue.js

I was wondering if it is possible to loop through multiple custom components in a carousel in Vueitfy?
I have imported and registered three components in my carousel.vue file below, however, I am not sure how you can loop through all the registered components in the v-carousel-item tag.
What I have in my carousel so far:
<template>
<v-carousel
hide-delimiter-background
delimiter-icon="mdi-minus"
width="100%"
height="700"
>
<v-carousel-item
v-for="(component, i) in components"
:key= i
reverse-transition="slide-fade"
transition="slide-fade"
>
</v-carousel-item>
</v-carousel>
</template>
<script>
import Carousel_s1 from './Carousel_s1.vue'
import Carousel_s2 from './Carousel_s2.vue'
import Carousel_s3 from './Carousel_s3.vue'
export default {
name: 'Carousel',
components: {
Carousel_s1,
Carousel_s2,
Carousel_s3,
},
(continue my code ...)

Inside your v-carousel-item you can use Vue's dynamic component mechanism to display the correct one:
<v-carousel-item
v-for="(component, i) in components"
:key="i"
reverse-transition="slide-fade"
transition="slide-fade"
<component :is="component"></component>
</v-carousel-item>
(BTW, you also should wrap your key value in quotes, as I did in my sample code)
Please note that this is not a Vuetify-specific feature but works in all Vue code :)

Related

how to delegate content from vue slots to web components slots?

The Problem
Let's say we have a page template written as a Web component in a shared library to keep the company design system consistent. That page has some slots:
export class PageTemplate extends LitElement {
static properties = {
title: { type: String },
};
render() {
return html`
<div>
<h1>${title}</h1>
<slot name="template-body"></slot>
<div class="some-special-styles">
<slot name="template-buttons"></slot>
</div>
</div>
`;
}
}
customElements.define("page-template", PageTemplate);
Then we use this template in a Vue (v3.2.45) application on a base component to be used in the same app by multiple pages.
//page-base.vue
<template>
<page-template title="My App Name">
<slot name="base-body"></slot>
<slot name="base-buttons"></slot>
</page-template>
</template>
Here, we will use the page base vue component on a specific page.
//login-page.vue
<template>
<PageBase>
<template #base-body>
<div slot="template-body">
<input placeholder="some special code"/>
</div>
</template>
<template #base-buttons>
<button slot="template-buttons">login</button>
<button slot="template-buttons">back</button>
</template>
</PageBase>
</template>
To make the login page components show inside that original page template web component; we need to declare the slot property on the leaf components like in <button slot="template-buttons">
How can I implement the Vue Page Base component to avoid the need to remember to set the slot property in every leaf vue component?
Things I've Tryied
I've tried to solve this using the vanilla web syntax below, but Vue appears not to dispatch that information to the final HTML:
//page-base.vue
<template>
<page-template title="My App Name">
<!-- this does not work -->
<slot name="base-body" slot="template-body"></slot>
<slot name="base-buttons" slot="template-buttons"></slot>
</page-template>
</template>
There was also an attempt (after a suggestion in the comments) to use a template as a ghost intermediate in the page base. But nothing was rendered at runtime.
//page-base.vue
<template>
<page-template title="My App Name">
<!-- i can't have that span because of some-special-styles applied in the template-->
<template slot="template-body"><slot name="base-body"></slot></template>
<template slot="template-buttons"><slot name="base-buttons"></slot></template>
</page-template>
</template>
The approach to using some middle element to make the connection (like below) enables content rendering. Still, it does not work for the project requirements because, for style reasons, I need that the final components be the top-most nodes in the page template slots.
//page-base.vue
<template>
<page-template title="My App Name">
<!-- although it runs, i can't have these spans because of some-special-styles applied in the template -->
<span slot="template-body"><slot name="base-body"></slot></span>
<span slot="template-buttons"><slot name="base-buttons"></slot></span>
</page-template>
</template>

Is there a way to set mixin data?

I'm working with vue-howler and for some reason, the data there is being passed using mixin, I don't see a way to access such mixin from the vue file script (much less do I find a way to change the data in it)
I want to show the progress of playing a music file in a vuetify slider, but due to being contained in a mixin, i get an error "Computed property was assigned to but it has no setter."
//MusicPlayerComponent.vue
<template>
<v-card flat width="500px" height="200px">
<v-flex class="info d-flex justify-center">
<v-btn icon large #click="togglePlayback">
<v-icon>
{{ playing ? 'mdi-pause' : 'mdi-play' }}
</v-icon>
</v-btn>
<v-slider v-model="progress" min="0" max="100">
</v-slider>
</v-card>
</template>
I don't need to show the script section of my vue file because there is literally nothing there, the "progress, playing, togglePlayback" properties and functions in the above code all come from that "mixin"
//MusicPlayerComponent.vue
<script lang="ts">
import { Component, Vue, Watch} from "vue-property-decorator"
// #ts-ignore
import VueHowler from 'vue-howler'
#Component({
mixins: [VueHowler]
})
export default class AudioPlayerComponent extends Vue {
}
</script>
You can use the seek property of vue-howler to get/set the position of playback for a sound. See docs for more props and options

The client-side rendered virtual DOM tree is not matching server-rendered content

Versions
nuxt: ^2.14.12
node: v14.15.4
Reproduction
Hello everyone and thank you in advance.
I have a strange issue that I don't really understand what's the problem and how to deal with it.
I have installed a fresh nuxt ssr project.
I'm getting the following warning
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
I have three simple components: Form, Input, Button.
Form.vue
<template>
<form v-bind="$attrs" class="w-full" #submit.prevent="$emit('submitted')">
<div class="space-y-2 mb-4">
<slot name="fields" />
</div>
<slot name="button" />
</div>
</form>
</template>
<script>
export default {
computed: {
hasFields() {
return !!this.$slots.fields
},
},
}
</script>
Input.vue
<template>
<div class="relative w-full">
<input class="form-input block w-full" />
</div>
</template>
<script>
export default {
inheritAttrs: false,
}
</script>
Button.vue
<template>
<button
type="submit"
class="relative btn inline-flex items-center justify-center transition ease-in-out duration-150"
>
Save
</button>
</template>
<script>
export default {}
</script>
I use my components in pages/index.vue like this:
<template>
<div>
<Form>
<template #fields>
<Input />
<Input />
</template>
<template #button>
<Button />
</template>
</Form>
<Form>
<template #fields>
<Input />
<Input />
</template>
<template #button>
<Button />
</template>
</Form>
</div>
</template>
<script>
export default {}
</script>
If i use the Form component only once in the view i don't get the warning.
If i use it twice i get it.
Steps to reproduce
Reproduction link
Install a fresh nuxt ssr project.
Create the components as in the reproduction link
What is Expected?
All the components to render normally without any warnings or errors.
What is actually happening?
I get the following warning.
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
Some extra notes
I know that wrapping the whole thing inside a <client-only> fixes the problem but i want to understand why is this happening in order to avoid it in future cases.
Also if I remove components: true from nuxt.config.js and import the components normally again the warning is gone.
Changing the name of the components eg Button -> TheButton won't fix the problem. You can see the reproduction here.
<script>
import Input from '~/components/Input'
import Button from '~/components/Button'
import Form from '~/components/Form'
export default {
components: { Form, Button, Input}
}
</script>
There seems to be one or more components which are not supported in "Universal" Mode, i.e. they might have code which isn't being executed correctly on server end.
Please try finding that component which you think can cause an issue and wrap that component with .
Here's the link for more information: https://nuxtjs.org/docs/2.x/features/nuxt-components#the-client-only-component

Vuetify custom v-text-field component is not updating the v-model

I’m following this documentation: https://v2.vuejs.org/v2/guide/components.html
I created custom v-text-field component which looks like that:
<template>
<div>
<v-text-field
:label="label"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"></v-text-field>
</div>
</template>
<script>
export default {
name: "txtbox",
props: ['value', 'label'],
}
</script>
I implemented it in my main component almost succesfully:
<txtbox
label="Name"
v-model="eventName"
/>
I don’t think it is necessary to paste all the code, but if it is I will edit the post. Here is how it works:
I have a list, when i click on the list element the text-field displays content of it, this works fine. Sadly when I’m editing the content of text-field the v-model value is not updating. I can also add that it works fine with normal (like in the docs) instead of . Is there anything I can do to make it work, or should i use simple input ?
Thanks
When you want to $emit the new value, you just have to emit the $event, and not $event.target.value
<template>
<div>
<v-text-field
:label="label"
v-bind:value="value"
v-on:input="$emit('input', $event)"></v-text-field>
</div>
</template>
v-on:input can also be shortened to just #input

Dynamically adding vue components

pls, am trying to add some components dynamically in vue so that i can easily create some tabs, the components are all stored in an array, but when i looped through each of those components, it displayed the name of the components instead of the content of the components, below is my code
<template>
<v-card>
<v-tabs color="#4FC3F7" slider-color="#004D40" right grow>
<v-tab ripple v-for="(ttab, index) in tabss" :key="index">{{ttab}}</v-tab>
<v-tab-item v-for="(tabCont, index) in tabConts" :key="index">
{{tabCont}}
</v-tab-item>
</v-tabs>
</v-card>
</template>
<script>
import ProfileComponents from './Profile.vue'
import PasswordsComponents from './Passwords.vue'
import ProjectsComponents from './Projects.vue'
import FiniancialsComponents from './Finiancials.vue'
import VerificationsComponents from './Verifications.vue'
export default {
data() {
return {
tabss:['Profile','Passwords','Projects','Finiancials','Verifications'
],
tabConts:['<ProfileComponents/>','<PasswordsComponents/>','<ProjectsComponents/>','<FiniancialsComponents/>','<VerificationsComponents/>'
],
};
},
components:{
ProfileComponents, PasswordsComponents, ProjectsComponents, FiniancialsComponents, VerificationsComponents
}
}
</script>
pls what am i doing wrong
For starters, tabConts is just an array of strings, so you're getting what you are asking for.
You probably want to use the 'component' component, which lets you specify the name of the component to insert as a property:
<component v-bind:is="componentName"></component>
So your template changes to something like this:
<template>
<v-card>
<v-tabs color="#4FC3F7" slider-color="#004D40" right grow>
<v-tab ripple v-for="(ttab, index) in tabss" :key="index">{{ttab}}</v-tab>
<v-tab-item v-for="(tabCont, index) in tabConts" :key="index">
<component :is="tabCont"></component>
</v-tab-item>
</v-tabs>
</v-card>
</template>
This assumes the components are registering themselves correctly, etc., but this should get you closer to a solution.