Is it possible to create parent (wrapper) components in Vue? I've looked and I haven't been able to find anything
What I have in mind is the following (the v-something components are from the vuetify library):
//cardWrapper.js
<template>
<v-card>
<v-row>
<v-col>
</v-col>
</v-row>
</v-card>
<template>
<script>
export default {
blabla
}
</script>
then this should somehow be available so that I can in the main file
// index.vue
<template>
<cardWrapper>
<v-btn>Click Me!</v-btn>
</cardWrapper>
</template>
I'm guessing this is a straightforward process and that I simply haven't been googling it correctly.
The only thing I've been able to find was to use dynamic components, but I would rather not pass components as properties
Here's the answer:
custom component
//custom-parent.vue
<template>
<custom-parent>
<slot/>
</custom-parent>
</template>
main file
//index.vue
<template>
<custom-parent>
<a>Hellohello</a>
</custom-parent>
</template>
Related
Below is the template of my App.vue.
It employs Vuetify's <v-main> and <v-app-bar> UI architecture.
Now I'm wondering how to achieve inter-component communication between the component that lives inside <v-main> and the component that lives inside <v-app-bar>.
<template>
<v-app>
<v-app-bar app color="primary" dark>
<ReadingSelector
:selectedReading="selectedReading"/>
</v-app-bar>
<v-main>
<router-view></router-view>
</v-main>
</v-app>
</template>
My routes contain a single component:
const routes = [
{ path: '/', component: Controller }
]
What is the most elegant and simple way to proceed architecturally?
Is Vuex the answer or is there a better way?
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
I probably don't understand how it should be done. I spent a few hours to achieve this functionality but with no luck. Here is what I have:
Child
<template>
<div>
Data from dialog: {{aaa}}
</div>
</template>
<script>
export default {
name: 'frm',
props: [
'aaa'
]
}
</script>
Parent:
<template>
<div>
<slot :aaa="some"></slot>
</div>
</template>
<script>
export default {
name: 'dlg',
data: () => ({
some: 'data from dialog'
})
}
</script>
View:
<template>
<div>
<dlg>
<frm></frm>
</dlg>
</div>
</template>
<script>
import Dialog from '#/components/dialog.vue'
import Frm from '#/components/frm.vue'
export default {
name: "View",
components: {
'dlg': Dialog,
'frm': Frm
}
};
</script>
Edit: Real code
dialog-template:
<template>
<v-dialog
v-model="internal.dialogOpened"
>
<!-- ... -->
<slot :aaa="'dsada'"></slot>
</v-dialog>
</template>
details-task-dialog:
<template>
<dlg-template large position='right' :onclose="close" :load="loadRetry">
<task-details-form /> <!-- just regular component in which I want to get value passed through slot in dialog-template -->
</dlg-template>
</template>
<script>
import DlgTemplate from '#/components/site/dialogs/dialog-template.vue'
export default {
// ...
components: {
'dlg-template': DlgTemplate,
'task-details-form': DetailsForm,
},
I want to avoid passing prop in View but I don't know how :/ I've read about 'slot-scope' unfortunately with no success. How to achieve such functionality?
Edit: real code
Based on your real world code, you were only missing the attachment of the scope, see below.
dialog-template:
<template>
<v-dialog v-model="internal.dialogOpened">
<!-- ... -->
<slot :aaa="'dsada'"></slot>
</v-dialog>
</template>
details-task-dialog:
<template>
<dlg-template large position='right' :onclose="close" :load="loadRetry">
<task-details-form v-slot="{ aaa }">
<!-- you can use the var `aaa` here -->
</task-details-form>
</dlg-template>
</template>
I'd still wager if you want to use aaa inside task-details-form component you have to pass it down as a prop. But it looks wierd to me, because I'm unsure of the execution order right now (v-slot vs v-bind), but try it like this:
<template>
<dlg-template large position='right' :onclose="close" :load="loadRetry">
<task-details-form v-slot="{ aaa }" :your-a-prop-name="aaa" />
</dlg-template>
</template>
Edit 2: after testing
v-bind shorthand is not working on <slot>:
dialog-template:
<template>
<v-dialog v-model="internal.dialogOpened">
<!-- ... -->
<slot v-bind:aaa="'dsada'"></slot>
</v-dialog>
</template>
details-task-dialog:
<template>
<dlg-template large position='right' :onclose="close" :load="loadRetry">
<template v-slot="{ aaa }"> <!-- has to preceed v-bind -->
<task-details-form :propertyOnComponent="aaa" /> <!-- now you cand bind it -->
</template>
</dlg-template>
</template>
Original:
I think you misunderstood slots. Check the docs:
That slot has access to the same instance properties (i.e. the same “scope”) as the rest of the template. The slot does not have access to child’s scope.
Slots
So you could do that, but then your code becomes:
<template>
<div>
<dlg>
<frm>
<child :aaa=“dialogData” />
</frm>
</dlg>
</div>
</template>
Frm:
<template>
<div>
From component
<slot></slot>
</div>
</template>
If you would define a slot on frm as you are suggesting, you would be able to fill that slot with a specific template and you can receive(!) the scope for that slot.
The deprecated slot-scope which you mentioned would provide you with a bound context from the child to be exposed in your overriding slot in the parent, that’s the opposite of what you want.
Just out of curiosity, why not send down the dialog data to the form as a property? That’s exactly what it’s for.
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.
I've got a problem with my vue-router and v-dialogs (vuetify.js components) inside different router-views.
My App.vue looks like this:
<template>
<transition>
<keep-alive>
<router-view/>
</keep-alive>
</transition>
</template>
Inside each router-view I have a component:
<template>
<v-app>
<app-header></app-header>
<v-content></v-content>
<app-footer></app-footer>
<!-- a couple of dialogs here -->
<v-dialog v-model="someData.show"></v-dialog>
<v-dialog v-model="anotherData.show"></v-dialog>
<v-dialog v-model="yetAnotherData.show"></v-dialog>
</v-app>
</template>
When I switch between different router-views and open dialogs overlay shows, but the dialog doesn't. Except for the router-view which was first loaded with the page.
What seems to be the problem? Does is have something to do with the way I define there routes or components?
You check full code over here: https://github.com/websanya/gkp7-app/
Please, help!
In fact I should've used only one v-app outside of router-view in App.vue file.
<template>
<!-- OVER HERE -->
<v-app>
<transition>
<keep-alive>
<router-view/>
</keep-alive>
</transition>
</v-app>
<!-- / OVER HERE -->
</template>
Works like a charm.