Vue slots props inside blade template - vue.js

I have a Vue3 application that mounts on a blade/laravel. In one blade temlate, I have a Vue3 component (zest-dropzone) in which I insert a slot:
<template>
...
<slot name="hits" :button-label="buttonLabel" :files="files" :type="type" :state="state"></slot>
</template>
<script>
...
</script>
Inside the blade template, I have the following:
<zest-dropzone
accepted-files=".psd,application/pdf,audio/*,image/*,video/*"
button-label="{{ Lang::get('admin/button.edit') }}"
categories="{{ json_encode($categories) }}"
type="files">
<template #hits="hitsProps">
#{{ hitsProps.type }}
<zest-dropzone-files-preview :hitsProps="hitsProps" :button-label="buttonLabel" :files="files" :type="type" :state="state"></zest-dropzone-files-preview>
</template>
</zest-dropzone>
ZestDropzoneFilesPreview is another component which is registered globally and is technically rendered on the page, however the props are never coming no matter what I try.
Within the blade template, #{{ hitsProps.type }} renders correctly and the value type exists on hitsProps, however when I try to pass it in the next component, it doesn't come through and I get undefined inside ZestDropzoneFilesPreview.
Anyone knows how to deal with this? Thanks.

Fixed it, props were not passed accordingly (hitsProps -> hits-props).

Related

Vue component within code block, Vue attempting to render the template

i'm trying to display example Vue component's within my documentation, however Vue is also recognizing the template within my Vue component.
vehicle-documents is not a registered component, and is also put into the following code:
Vue.config.ignoredElements = ['slide', 'slider', 'vehicle-documents'];
So Vue is ignoring the component itself:
If you want the modal make sure you add the click event and call the `open` function, and pass the `document` into this function call, as seen below.
```html
<vehicle-documents class="app" vehicle-id="">
<template v-slot:default="slotProps">
<button #click="slotProps.open(slotProps.document)">
{{ slotProps.document.name }}
</button>
</template>
</vehicle-documents>
```
How can I make Vue ignore the template block? I need Vue on this page, so it's not a simple case of just removing Vue.
Try this, add v-pre and type="text/x-template"
<vehicle-documents class="app" vehicle-id="">
<template v-pre type="text/x-template">
<button #click="slotProps.open(slotProps.document)">
{{ slotProps.document.name }}
</button>
</template>
</vehicle-documents>

My dynamic component (layout) doesn't work with named slots in vuejs

I have problems to combine dynamic generated layouts with named slots.
To define my layouts I'm using "component :is"
//app.vue
<template>
<component :is="layout">
<router-view />
</component>
</template>
<script>
computed: {
layout() {
const layout = this.$route.meta.layout || 'default'
return () => import(`#/app/layouts/${layout}.vue`)
}
},
</script>
//layouts/default.vue
<template>
<div>
<div>
<slot name="header" />
</div>
<div>
<div>
<slot name="sidebar" />
</div>
<div>
<slot name="default"/>
</div>
</div>
</div>
</template>
// views/page.vue
<template>
<div>
<template #header>
<h1>Primitives</h1>
</template>
<template #sidebar>
<ul>
<li v-for="primitive in sections.sections" :key="primitive">
<router-link :to="`/primitives/${primitive}`">{{primitive}}</router-link>
</li>
</ul>
</template>
<template #default>
<router-view :key="$router.path" />
</template>
</div>
</template>
But now I get this error inside my code
'v-slot' directive must be owned by a custom element, but 'div' is not.
and console displays this error
<\template v-slot> can only appear at the root level inside the receiving component
If I remove the main div I get the error
The template root requires exactly one element.
What I'm doing wrong?
This is not easy to explain so please cope with me...
I really understand what you are trying to do but unfortunately it is not possible in Vue.
Reason for that is slots are more template compiler feature than runtime feature of Vue. What I mean by that ? When Vue template compiler sees something like <template #header>, it will take the inner content and compile it into a function returning virtual DOM elements. This function must be passed to some component which can call it and include the result in it's own virtual DOM it is generating. To do that template compiler needs to know to what component it should pass the function (that is the real meaning of 'v-slot' directive must be owned by a custom element, but 'div' is not. error message...ie compiler is "looking" for a component to pass the slot content to...)
But you are trying to use the slots as if they were "discoverable" at runtime. For your code to work the dynamic layout component must at runtime somehow discover that it's child (also dynamic thanks to <router-view />) has some slot content it can use. And this is not how slots work in Vue. You can pass the slot content your component receives from parent to a child components but do not expect that parent component (layout in this case) can "discover" slot content defined in it's child components...
Unfortunately only solution for your problem is to import the layout component in every "page" and use it as a root element in the template. You can use mixins to reduce code duplication (to define layout computed)
#/mixins/withLayout.js
export default = {
computed: {
layout() {
const layout = this.$route.meta.layout || 'default'
return () => import(`#/app/layouts/${layout}.vue`)
}
}
}
views/page.vue
<template>
<component :is="layout">
<template #header>
<h1>Primitives</h1>
</template>
<template #sidebar>
<ul>
<li v-for="primitive in sections.sections" :key="primitive">
<router-link :to="`/primitives/${primitive}`">{{primitive}}</router-link>
</li>
</ul>
</template>
<template #default>
<router-view :key="$router.path" />
</template>
</component>
</template>
<script>
import withLayout from '#/mixins/withLayout'
export default {
mixins: [withLayout]
}
</script>

How to pass v-model to parent in vue-multiselect

i have two components.
One is vselect template and wrapper for vue-multiselect.
<template lang="pug">
field-wrapper.field(:label="label" :caption="caption" :error="error")
multiselect(v-model="value" :options="options")
</template>
Second is page.vue where im including it
vselect(v-model="select.value" :options='select.options')
p {{ select.value }}
But v-model works only inside vselect, how i cant pass selected data to page.vue, from vselect? I cant use new method for emit in page.vue. Vue-multiselect works only with v-model i guess?
When i have a case with input, what works for me
<template lang="pug">
field-wrapper.field(:label="label" :caption="caption" :error="error")
input.form-input(:type="computedType" :value="value" :disabled="disabled" :placeholder="placeholder" #keyup="removeError" #input="$emit('input', $event.target.value)")
</template>
#input="$emit('input', $event.target.value) - i solve problem like this, but ints not work with plugin vuemultiselect

Register multiple Vue components in parent component

I have a global sidebar component TheSidebar.vue:
<template>
<aside>
<slot></slot>
</aside>
</template>
In Blogs.vue (a page component) I try to register two components.
<template>
<div>
<h1>Experiences</h1>
<TheSidebar>
<SearchBlog />
<CategoryCheckboxFilter />
</TheSidebar>
<ExperienceList />
</div>
</template>
It seems like I cannot register two components in a slot?
Is this a good setup anyway and who do I have to achieve this?
Update
It's just working fine now and I can register more than one component in a <slot />. I think some webpack building issue before.

How do I use conditional rendering on template tag?

According to the Vue documentation I should be able to add the v-if condition to the <template> tag:
<template v-if="false">
<div>Invisible text</div>
</template>
But this will not hide the element, however it does work when added to the child element:
<template>
<div v-if="false">Invisible text</div>
</template>
Any suggestions?
I'm including the template in another .vue file:
<template>
<div id="app">
<H1 class= "main-title">Title</H1>
<span class="components">
<testtemplate></testtemplate>
</span>
</div>
</template>
The template tag of a single-file component is not rendered by Vue like normal <template> tags. It is simply one of the placeholders, along with <script> and <style> that vue-loader uses to build the component. The root element of that template is what will be the root in the component.
But, even if it worked the way you want, there would be no difference between your first and second example. Using v-if on the root will prevent the entire component's template from rendering if set to false.
Had this problem with VUE3. Using SFC just nest tag template inside another tag template :
<template>
<template v-if="false">
You won't see this
</template>
</template>