Vue.js: Loading template (or div) when user clicks button? - vue.js

So I currently have a template sitting in a ".vue" file like so:
<template>
<div id="dataAttachToMe"></div>
</template>
I don't want this to load, unless a user clicks a button, something like
<button #click="loadTheTemplateAbove">See Data</button>
I've tried using this example:https://v2.vuejs.org/v2/guide/conditional.html#Controlling-Reusable-Elements-with-key. But it says something like "Component template should contain exactly one root element" in the error message.
I need more than a show/hide here I think, something that can initiate the template dynamically.
<template>
<div id="data">
<button #click="loadTemplate">Load the template</button>
<div v-if="buttonClicked">
<div id="dataAttachedToThisDiv"></div>
</div>
</div>
</template>

The error you are getting, means that there is more than one root element inside <template></template> tag.
It is required in Vue.js (and other template based frameworks/libraries) to have only one root element.
This will NOT work:
<template>
<div id="dataAttachToMe"></div>
<button #click="loadTheTemplateAbove">See Data</button>
</template>
This will work:
<template>
<div id="someRootDiv">
<div id="dataAttachToMe">Some data</div>
<button #click="loadTheTemplateAbove">See Data</button>
</div>
</template>
Here is a code example (App.vue) of what you are trying to achieve:
Basic idea: we have to create a variable, that will be changed upon button click. We add v-if directive that depends on that variable and will handle element's visibility.

Welcome to StackOverflow. When you get the error Component template should contain exactly one root element it means that you can only have one root element in your template. You can fix that error by wrapping everything in a blank div like so
<template>
<div>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
</div>
</template>
Please edit your post and place you <script> tag. Conditional Rendering requires a data field of a boolean that you can place in your if statement on your template
<template>
<div>
<div v-if="show">{{message}}</div>
<div v-if="#show">Not Showing when show is set to false</div>
<button v-on:click="show = true">Show</button>
</div>
</template>
<script>
module.exports {
data: function () {
message: 'Hello Vue!',
show: false
}
}
</script>

Related

The Bootstrap-vue3 table does not add buttons to each row of data

I'm trying to add a button to the bootstrap table using Vue3, but I ran into the following problem.
The logic of the button is stored in the parent component, and I plan to $emit on the logic from there. But in order for the button to delete a certain row, for example, I need to pass a special ID, I can't pass it to the ID, because I don't understand how to iterate through the data array in the bootstrap table correctly.
Maybe there is a soft and correct way to solve this problem?
ChildComponent.vue
<template>
<div v-if="data.length !== 0">
<div class="card inline" >
<div>
<b-table striped hover :items="data">
<button #click="$emit('remove', hereIneedTheID)">Remove</button>
</b-table>
</div>
</div>
</div>
<div class="card center" v-else>
<h4>No data available in the list</h4>
<button class="btn" #click="$emit('load')">Load list of data</button>
</div>
</template>
<script>
export default {
name: "AppDataList",
emits: ['load', 'remove'],
props: ['data']
}
</script>

Components as slot content Vue3

I wonder how to add components as slot content. Instead of doing it like:
<template v-slot:content>CONTENT HERE</template>
I'd like to pass a component.
PkDynModalCenter:
<div class="...">
<div id="modalIndicator" class="...">
<slot name="content"></slot>
</div>
</div>
Parent:
<PkDynModalCenter v-if="togglePayment" #closeModal="togglePayment = false">
<PaymentTemplate :info="voucherInfo" name="content"></PaymentTemplate>
</PkDynModalCenter>
But it's not displayed. Docs are very vague there...
Have a look at the docs for named slots: https://vuejs.org/guide/components/slots.html
You can only use your parent code with the default slot, so your PkDynModalCenter should look like this:
<div class="...">
<div id="modalIndicator" class="...">
<slot></slot> <!-- no name → default slot -->
</div>
</div>
With your current code for the modal, you can only call it like you did in your first code snippet.

Using a component inside another component in VueJS

While I was reviewing headlessui's menu component, I saw the use of 2 components that are nested like the following: (see: https://headlessui.dev/vue/menu)
<template>
<Menu>
<MenuButton>More</MenuButton>
<MenuItems>
<MenuItem v-slot="{ active }">
// some content
</MenuItem>
</MenuItems>
</Menue>
</template>
So as you may see, there is a MenuItem component inside of the MenuItems component. And I need something similar to that so I can use a template and put another component's result into that template.
Here the example of what I am trying to do:
<!-- HeadingComponent.vue -->
<div class="group">
<div class="head">
{{ title }} <button>Create New</button>
</div>
<div class="content">
<!-- I want to put some component's rendered content here -->
</div>
</div>
And this is, let's say, a page where I want to use the common component.
<!-- Blog.vue -->
<HeadingComponent :title="Posts">
<BlogPostsComponent :post="someArray"/> <!-- Some other component which may vary -->
</HeadingComponent>
The question
What kind of changes do I need to do in the component HeadingComponent.vue so it works as I expected?
Slots are a good way to add a component to another or even simple html
docs : https://fr.vuejs.org/v2/guide/components-slots.html
<h1>Vue JS Slots Application</h1>
<div id="app">
<slots>
<template slot="slotA"><pre>Slot A Content from parent.</pre></template>
<template><i>Parent Component Content.</i></template>
</slots>
<hr/>
<slots>
<template slot="slotB">Replace Slot B Default Content</template>
<template><b>Replace Default Slot Content.</b></template>
</slots>
</div>
<template id="aside">
<div>
<h3>My Slots App</h3>
<slot>Default Slot Content</slot><br>
<slot name="slotA"></slot><br>
<slot name="slotB"></slot><br>
</div>
</template>
Example of codepen :
https://codepen.io/brian_kim/pen/NpWKGe
Just in a short time, I found something like slots in VueJS which is definitely what I was looking for.
Here is the guide page:
https://v2.vuejs.org/v2/guide/components-slots
What I did in my problem is that I put <slot></slot> tags inside div whose class is content, and then the last sample I gave (Blog.vue) has worked.
<!-- HeadingComponent.vue -->
<div class="group">
<div class="head">
{{ title }} <button>Create New</button>
</div>
<div class="content">
<!-- I want to put some component's rendered content here -->
<slot></slot>
</div>
</div>

VueJS Modal component inside component

I have a component like this:
<test></test>
I declare this as follows:
Vue.component('test', {
data: {
showModal: true
},
methods: {
displayComponentModalDialog: function() {
this.showModal = true;
}
},
template: `<button #click='displayComponentModalDialog'>test</button>`
});
The <test></test> component is then placed somewhere inside the <div id="#app"> wrapper.
var app = new Vue({
router,
el: '#app',
// etc.
})
Now, I want to display another component inside the test component. So in this case I want a dialog to appear after I click the button in test component. I am not able to achieve this.
What I did is adding a new component:
Vue.component('dialog', {
template: '#dialog-template'
});
And then the following code, although I do not know for sure where to put it.
<!-- template for the modal component -->
<script type="text/x-template" id="dialog-template">
<transition name="dialog">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="btn btn-primary" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<!-- use the modal component, pass in the prop -->
<dialog v-if="showModal" #close="showModal = false">
<h3 slot="header">header</h3>
<p slot="body">
test
</p>
</dialog>
I tried putting this code inside the <test></test> but doesn't work. If I put it inside the template attribute in the component structure, it complains about only one root element.
So it is clear I miss some basic conception how this actually works in VueJS. Someone can help me clarify? Thanks.
As far as I can see your component indeed doesn't have a root tag. Templates have to have a root tag.
This is NOT a valid Vue template:
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
This IS a valid Vue template:
<div>
<div>
<h1>Stuff</h1>
</div>
<h2>Other stuff</h2>
</div>
Note that in the second version we have a single root element for the template, a <div>, whereas in the first one we do not.
You have both a <script></script> and a <dialog></dialog> in your component template.
if you want to add another component in your test component . you can use slot on it.
You can refer to this documentation: https://v2.vuejs.org/v2/guide/components-slots.html
Example:
//component 1
<template>
<div id="modal">
// do something for your modal here.
<slot></slot> // reserve area for your another html or component.
</div>
</template>
// component 2
<template>
<your-modal-component>
<another-component>
</your-modal-component>
</template>

VueJS: Is It Possible to Automatically Include One Component in Another Component

I would like to automatically include the contents of one component in a named slot of another component. I.e., something like this:
Vue.component('comp-one', {
template: `
<div class="comps>
<div class="comp-two">
<slot name="compTwo"></slot>
</div>
<div class="comp-one">
<slot></slot>
</div>
</div>
`
})
Vue.component('comp-two', {
slot: 'compTwo',
template: `
<div class="sub-comp-two">
<!-- content goes here -->
<slot></slot>
</div>
`
})
The idea is that if someone uses <comp-two>Some content</comp-two>, it will automatically get added to the slot compTwo in comp-one. Is there a way to do this?
NOTE: I made up slot: 'compTwo'. Just trying to illustrate what I'd like to accomplish.