How can I load different components in the same page - vue.js

Each user type in my app needs to have a different dashboard, so, at the moment, my admin vue looks like the following:
<template>
<main id="admin-main">
<header id="admin-dashboard-header" class="jumbotron">
<div>
<h1>Job Dashboard</h1>
<p>Worker > Dashboard</p>
</div>
</header>
<div class="row container">
<div class="col-4">
<ul class="list-group text-center">
<li class="list-group-item active">Dashboard</li>
<li class="list-group-item">Companies</li>
<li class="list-group-item">Jobs</li>
<li class="list-group-item">Candidates</li>
</ul>
</div>
<div class="col-8">
All components must load here
</div>
</div>
</main>
</template>
<style scoped>
h1{
font-size: 50px;
}
</style>
Ideally, each list item(Companies, Jobs, Candidates) must load their respective component.
So, for instance, how can I load jobs component in this same page when I click on the jobs list item?

One solution would be to use dynamic components. See: https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components
You can see an example I made here: https://codepen.io/bergur/pen/bPEJdB
In my Vue app I've made a data property called selectedComponent, and defined a method that sets that property according to the parameter
setComponent(name) {
this.selectedComponent = name
}
You then invoke that function with something like:
<button #click="setComponent('menuList')">Menu List</button>
And here is the real magic
<component :is="selectedComponent" />
So when I press the button. The data property selectedComponent gets the value menuList which is the registered component.
The component tag then renders that component.

Related

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>

Vue refs undefined in modal

I do have a for loop and inside i want to have a modal for each image
<div class="col pb-3" v-for="(item, index ) in img" :key="index" style="width: 300px;height:auto;">
<img v-b-modal="'modal-'+index" :ref="'image'" #mouseover="mouseOver" #mouseleave="mouseOut" /><br>
<b-modal :id="'modal-'+index" title="BootstrapVue">
<p class="my-4">Hello from modal - {{index}}</p>
<img :ref="'imagex'" />
</b-modal>
<div class="progress pt-2 mt-1" style="width: 100px;margin: 0 auto;">
<div class="progress-bar " :style="[{'width':width[index]+'px'}]" role="progressbar"
aria-valuenow="0" ref="'progress'" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
In methods i am giving src value to each image that has :ref="'image'" and i can actually give a src to them its work fine but, i also want be able to give src value images in modal. Its called :ref="'imagex'" but its undefined.
this.$refs.image[i].src = event.target.result //works
this.$refs.imagex[i].src = event.target.result //undefined
What is the problem an is there anyway to solve it ?
When used on elements/components with v-for, the registered reference will be an Array containing DOM nodes or component instances.
An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you cannot access them on the initial render - they don’t exist yet! $refs is also non-reactive, therefore you should not attempt to use it in templates for data-binding.
.
can use it in events and only at mounted function.
https://v2.vuejs.org/v2/api/#ref

Vuejs Variables Not Displaying on Modal

I have a script that needs to output the results of an answer on a modal window. But currently it isn't rendering. The results output correctly outside of the modal HTML; even inspecting the modal source when it is visible shows the data isn't rendering; i.e. the results aren't hidden from view, they aren't calculated at all.
The full source is at
http://www.sic-parvis-magna.com/sicpm/mayan-vue/index.html
The variables in question are userAnswer, userAnswerDisplay, and userMessage
<div class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<section class="modal-card-body">
<div v-if="userAnswer !== -1">
<div id="user-answer" v-html="userAnswerDisplay"></div>
<div id="user-answer-message" v-html="userMessage"></div>
<div id="user-hint"></div>
</div>
</section>
<footer class="modal-card-foot">
<button class="button is-success">Save changes</button>
<button class="button modal-close">Cancel</button>
</footer>
<button class="modal-close is-large" aria-label="close"></button>
</div>
</div>
The problem is your modal template is outside the Vue app (i.e., section#mainapp), so that template is not processed by Vue:
<section id="mainapp">...</section>
<div class="modal">...</div> <!-- FIXME: Move this into section above -->
Move the modal into section#mainapp for the computed properties to be evaluated.
demo

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

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>

Some part of Vue2 component's template does not render

I have a vue2 app (called 'renderer-app') with a component as its child (called 'section-renderer'), which in turn has a child component. In the parent component (section-renderer) I have a template option in which the multiple components are added to the parent component:
template:
<div>
<component v-for="(item, index) in layoutArray" :is="item.template" :cardObj="item.cardObj" :key="item.id"></component>
<!--the above component gets rendered as it should, but the rest of the template is not rendered-->
<div class="parallax-container">
<div class="parallax">
<img src="./images/banner2.jpg">
</div>
<div class="advertisement-text-box">
<p class="advertisement-header">some header</p>
<p class="advertisement-text">some text</p>
</div>
</div>
</div>
As I have shown above in the comment line, the child component gets rendered multiple times as it should, but the rest of the template which should be rendered once per parent component does not render.
Strangely enough, if I insert a div with text in it between the two, the rest of the template renders too. So this works (of course with an unwanted line):
template:
<div>
<component v-for="(item, index) in layoutArray" :is="item.template" :cardObj="item.cardObj" :key="item.id"></component>
<div>extra</div> <!--the extra div with text-->
<div class="parallax-container">
<div class="parallax"><img src="./images/banner2.jpg"></div>
<div class="advertisement-text-box">
<p class="advertisement-header">some header</p>
<p class="advertisement-text">some text</p>
</div>
</div>
</div>
I tried various positioning of the div around the child component and the rest of the template, but none seemed to work. Any help would be appreciated.