I have this TabPanel where I am rendering multiple tabs. Each Panel inside TabPanel uses/extends Panel where I am using slots. However, during tab switch content of Tabs are getting merged.
<template>
<div class>
<div class>
<ul class>
<li
style="display: inline-block; padding:10px; margin: 10px; border: 1px solid #ccc"
v-for="(panel, index) in panels"
:key="index"
#click="selectTab(index)"
:ref="'panel' + index"
>{{ panel.title }}</li>
</ul>
</div>
<div class>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "TabPanel",
data() {
return {
panels: [],
selectedIndex: 0
};
},
methods: {
selectTab(panelIndex) {
this.selectedIndex = panelIndex;
this.panels.forEach((panel, index) => {
panel.isActive = index === panelIndex;
});
}
},
created() {
this.panels = this.$children;
},
mounted() {
this.selectTab(0);
}
};
</script>
Panel code
<template>
<div v-show="isActive">
<slot></slot>
</div>
</template>
<script>
export default {
name: "Panel",
props: {
title: {
type: String,
required: true
},
panelId: {
type: String,
required: true
}
},
data() {
return {
isActive: true
};
}
};
</script>
Is there anyway to fix this issue. This is the CodeSandbox link to demonstrate this issue since its easier to visualize problem that way I think.
Dashboard.vue and RosePanel.vue changes isActive data but they are not doing nothing whit this.
One option is to set a v-show/v-if to each own <Panel>:
<Panel v-show="isActive" :title="title" :panelId="panelId">Content from Dashboard</Panel>
CodeSandbox: https://codesandbox.io/s/charming-hamilton-jz1og
The simplest way to fix the issue is to wrap all components in <Panel>-s:
<TabPanel>
<Panel title="Dashboard" panel-id="dashboard">
<Dashboard></Dashboard>
</Panel>
<Panel title="Test" panel-id="test">Content from Panel</Panel>
<Panel title="Rose Panel" panel-id="rose-panel">
<RosePanel></RosePanel>
</Panel>
</TabPanel>
https://codesandbox.io/s/eager-brown-6ethk?file=/src/App.vue
But this is probably not what you had in mind.
From what I see, you simply forgot to propagate the "is-active" property to the embedded panel:
<Panel :title="title" :panelId="panelId" :is-isActive="isActive">Content from Dashboard</Panel>
(e.x in the Dashboard Component)
Related
I would like to have responsive drawer, so tried to code in accordance with Quasar Docs, however, it was not resized properly when the screen size is being changed. In order to solve this, I used computed in the script. I think due to this computed, the function drawerClick not working.
When the drawer is on minimode, and one of menus are clicked, then the menu should be expanded, but the problem I have is it never expanded.
template
<template>
<q-drawer
v-model="drawer"
show-if-above
:mini="!drawer || miniState || miniStatus"
#click.capture="drawerClick"
:width="220"
:breakpoint="500"
bordered
:content-style="{ backgroundColor: '#f5f7f9' }"
id="side-menu"
>
<q-scroll-area class="fit">
<q-list padding>
<q-btn v-if="!miniState" flat left class="logo-btn">
<img src="~assets/os_logo.png" width="144px" height="24px" contain />
</q-btn>
<q-btn v-else flat left>
<img src="~assets/os_logo_no_text.png" width="24px" contain />
</q-btn>
<q-expansion-item
default-opened
v-for="(menu, index) in menus"
header-class="header-bg text-black"
expand-icon-class="text-gray"
>
<q-expansion-item
v-for="(sub, index) in menu.subMenus"
:key="index"
:label="sub.title"
expand-icon="none"
class="sub-content"
:to="{ name: sub.link }"
/>
</q-expansion-item>
</q-list>
</q-scroll-area>
</q-drawer>
</template>
script
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'SideMenu',
data() {
return {
drawer: false,
miniStatus: false,
switchToMini: 700
};
},
computed: {
miniState: function() {
return this.$q.screen.width < this.switchToMini;
}
},
methods: {
drawerClick(e) {
if (this.miniStatus) {
this.miniStatus = false;
e.stopPropagation();
}
}
}
});
</script>
I explained better here in this image
[1]: https://i.stack.imgur.com/PqYoc.png
I have four pictures, when I hover the mouse over them, a certain component is displayed from below, but I still need to bind the click event, that is, when I click on the picture, the component should be displayed; when the component is clicked again, the problem is that I cannot bind two events at once at the same time
I understand that when the user hovers over the component, it will be immediately displayed and the click event will be useless, but I will need it in the mobile version
You can also look at my code in codesandbox
<template>
<div>
<div class="enjoy_headline_container">
<div class="EnjoyGirlsContainer">
<div>
<h3 style="margin: 0"></h3>
</div>
<div class="EnjoyGirlsList">
<div
v-for="(chunk, index) in Math.ceil(EnjoyGirlsList.length / 2)"
:key="'chunk-' + index"
:class="'wrap-' + index"
>
<div
v-for="(item, index) in EnjoyGirlsList.slice(
(chunk - 1) * 2,
chunk * 2
)"
:key="'img-' + index"
class="EnjoyCard"
:class="'EnjoyCard-' + index"
>
<div v-on:click="isHidden = !isHidden">
<img
#mouseover="mouseOver(item, (hover = true))"
:src="item.imagePath"
alt="Snow"
/>
</div>
<div class="EnjoyCardContainer">
<div
:style="{ background: item.textColor }"
class="EnjoyCardChildContainer"
>
<h3 class="EnjoyCardChildContainerTitleName">
{{ item.titleName }}
</h3>
</div>
</div>
<div
v-if="selected === item && !isHidden"
class="below-all-description EnjoyGirlsHoverEffect"
>
<div class="next-to-description EnjoyGirlsHoverEffect">
<div
style="width: 100%; display: flex; justify-content: center"
v-for="(enjoy, index) in EnjoyGirlsList"
:key="index"
>
<div
#mouseleave="mouseout(enjoy, (hover = false))"
class="EnjoyGirlsChildHoverEffect"
>
<component
v-show="enjoy.hovered"
v-bind:is="enjoy.componentName"
></component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="!isHidden" class="below-all-description">
<template v-if="selected === null"></template>
<template v-else>
<div
style="width: 100%; display: flex; justify-content: center"
v-for="(enjoy, index) in EnjoyGirlsList"
:key="index"
>
<div
#mouseleave="mouseout(enjoy, (hover = false))"
class="EnjoyGirlsChildHoverEffect"
>
<component
v-show="enjoy.hovered"
v-bind:is="enjoy.componentName"
></component>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
import EnjoyBlue from "./components/EnjoyBlue";
import EnjoyGreen from "./components/EnjoyGreen";
import EnjoyYellow from "./components/EnjoyYellow";
import EnjoyRed from "./components/EnjoyRed";
export default {
name: "HomePage",
components: {
EnjoyRed,
EnjoyYellow,
EnjoyGreen,
EnjoyBlue,
},
data() {
return {
isHidden: false,
selected: null,
hover: false,
sectionGirlsListComponentsNames: [
"EnjoyRed",
"EnjoyYellow",
"EnjoyGreen",
"EnjoyBlue",
],
EnjoyGirlsList: [
{
imagePath: "https://i.ibb.co/mCpNXhG/IMG-6061-min.png",
titleName: "TEENS",
textColor: "#74C8C5",
hovered: false,
componentName: "EnjoyBlue",
},
{
imagePath: "https://i.ibb.co/WvJjwsN/Rectangle-2.png",
titleName: "MINXES",
textColor: "#76ED00",
hovered: false,
componentName: "EnjoyGreen",
},
{
imagePath: "https://i.ibb.co/7khc5f0/Rectangle-3.png",
titleName: "MILFS",
textColor: "#FFE600",
hovered: false,
componentName: "EnjoyYellow",
},
{
imagePath: "https://i.ibb.co/6nz97Bw/Rectangle-4.png",
titleName: "COURGARS",
textColor: "#CC003D",
hovered: false,
componentName: "EnjoyRed",
},
],
};
},
methods: {
mouseOver: function (enjoy) {
this.EnjoyGirlsList.forEach((enjoy) => (enjoy.hovered = false));
this.selected = enjoy;
enjoy.hovered = true;
if (this.hover) {
console.log("4949494");
}
},
mouseout: function (enjoy) {
this.selected = null;
enjoy.hovered = false;
},
mouseEnter: function () {},
Prev() {
this.$refs.carousel.prev();
},
showNext() {
this.$refs.carousel.next();
},
},
};
</script>
And so if you looked at this code in codesandbox (I left the link at the top), then you might have noticed that hover only works the first time after that it does not work, only the click event works
Your click event toggles isHidden. When you click on it you set isHidden to true. After that it won't show, if you hover over it since you are hiding it with v-if:
<div v-if="!isHidden" class="below-all-description">
...
</div>
Solution:
In your mouseOver function you explicitly have to set isHidden to false.
methods: {
mouseOver: function (enjoy) {
this.isHidden = false;
this.EnjoyGirlsList.forEach((enjoy) => (enjoy.hovered = false));
...
}
...
}
I have two pictures, when hovering over the first picture, a certain component is displayed and the second picture works in a similar way, which displays another component, my problems began when I decided to apply animation when hovering over the picture, that is, I wanted to make it appear a certain component with animation, but the problem is that the animation works only for the first component, and for the second component, not only the animation does not work, it is also not displayed, you can see my code in the sandbox
If you looked at my code, you might have noticed that I display components using v-for, but when I tried to display components manually (that is, without a loop), everything worked fine for me, that is, like this
<div style="margin-top: 200px;">
<slide-y-up-transition>
<RedExperience v-show="img1" key="img1"/>
</slide-y-up-transition>
<slide-y-up-transition>
<OrangeExperience v-show="img2" key="img2"/>
</slide-y-up-transition>
<slide-y-up-transition>
<GreenExperience v-show="img4" key="img4"/>
</slide-y-up-transition>
</div>
Here is my code from sandbox
<template>
<div>
<div style="display: flex; justify-content: center">
<div v-bind:key="index" v-for="(girl, index) in girls">
<img
style="width: 200px; height: 200px; margin: 5px"
#mouseover="mouseOver(girl)"
#mouseout="mouseout(girl)"
v-bind:src="girl.imgSrc"
alt="Snow"
/>
</div>
</div>
<slide-y-up-transition>
<component
v-for="(girl, index) in girls"
v-show="girl.hovered"
v-bind:key="index"
v-bind:is="girl.componentName"
></component>
</slide-y-up-transition>
</div>
</template>
<script>
import { SlideYUpTransition } from "vue2-transitions";
import MyFirstComponent from "./colors/myycomponent";
import myOtherComponent from "./colors/myothercomponent";
export default {
name: "HelloWorld",
components: {
MyFirstComponent,
myOtherComponent,
SlideYUpTransition,
},
data() {
return {
componentNames: ["MyFirstComponent", "myOtherComponent"],
girls: [
{
imgSrc:
"https://www.gettyimages.com/gi-resources/images/500px/983794168.jpg",
hovered: false,
hoverColor: "#337700",
componentName: "MyFirstComponent",
},
{
imgSrc:
"https://www.gettyimages.com/gi-resources/images/500px/983794168.jpg",
hovered: false,
hoverColor: "#123456",
componentName: "myOtherComponent",
},
],
};
},
methods: {
mouseOver: function (girl) {
girl.hovered = true;
},
mouseout: function (girl) {
girl.hovered = false;
},
},
};
</script>
the problem is in your loop, transitions can only be used on a single element.
So do your loop this way to solve it.
<div v-for="(girl, index) in girls" v-bind:key="index">
<slide-y-up-transition>
<component
v-show="girl.hovered"
v-bind:is="girl.componentName"
></component>
</slide-y-up-transition>
</div>
your full code has to be like this.
<template>
<div>
<div style="display: flex; justify-content: center">
<div v-bind:key="index" v-for="(girl, index) in girls">
<img
style="width: 200px; height: 200px; margin: 5px"
#mouseover="mouseOver(girl, index)"
#mouseout="mouseout(girl, index)"
v-bind:src="girl.imgSrc"
alt="Snow"
/>
</div>
</div>
<div v-for="(girl, index) in girls" v-bind:key="index">
<slide-y-up-transition >
<component
v-show="girl.hovered"
v-bind:is="girl.componentName"
></component>
</slide-y-up-transition>
</div>
</div>
</template>
<script>
import { SlideYUpTransition } from "vue2-transitions";
import MyFirstComponent from "./colors/myycomponent";
import myOtherComponent from "./colors/myothercomponent";
export default {
name: "HelloWorld",
components: {
MyFirstComponent,
myOtherComponent,
SlideYUpTransition,
},
data() {
return {
componentNames: ["MyFirstComponent", "myOtherComponent"],
girls: [
{
imgSrc:
"https://www.gettyimages.com/gi-resources/images/500px/983794168.jpg",
hovered: false,
hoverColor: "#337700",
componentName: "MyFirstComponent",
},
{
imgSrc:
"https://i.pinimg.com/originals/a9/76/af/a976af5c7bf3cc5b05a1b301334e0f68.jpg",
hovered: false,
hoverColor: "#123456",
componentName: "myOtherComponent",
},
],
};
},
methods: {
mouseOver: function (girl, index) {
this.girls[index].hovered = true;
},
mouseout: function (girl, index) {
this.girls[index].hovered = false;
},
},
};
</script>
i have a costume made Tabs and Tab from Laracasts Tabs Tutorial , and it work fine, but i need to load data when the tab is changed and i did that but when the data is loaded,
i need to render another component which have accordion and inside each accordion tab their some charts components need to be render also
so how can i render the accordion with the charts components when the Tabs tab is changed
Tabs Component:
<template>
<div class="tab-container -mt-px w-full">
<div class="tabs">
<ul class="list-reset flex border-b">
<li class="" v-for="(tab, index) in tabs" role="tab">
<a class="bg-white inline-block font-semibold hover:no-underline"
:class="[
{
'active-tab-link text-blue-dark border-l border-r active-tab-link-p': tab.isActive,
'text-blue hover:text-blue-darker non-active-tab-link-p': !tab.isActive
},
]"
:href="tab.href" #click="selectedTab(tab)">
{{tab.name}}
</a>
</li>
</ul>
</div>
<div class="tabs-details px-4 w-full">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "Tabs",
data() {
return {
tabs: []
};
},
created() {
this.tabs = this.$children;
// this.selectFirstTab();
},
methods: {
selectedTab(selectedTab) {
this.$emit('onTabChange', selectedTab);
this.tabs.map((tab, index) => {
tab.isActive = (tab.name === selectedTab.name)
});
},
}
}
</script>
Tab Component:
<template>
<div class="w-full" role="tabpanel" v-show="isActive">
<slot></slot>
</div>
</template>
<script>
import {isEmpty} from "../helpers/Helper";
export default {
name: "Tab",
props: {
name: {
type: String,
required: true
},
selected: {
type: Boolean,
default: false,
},
isFirst: {
type: Boolean,
default: false,
},
},
data() {
return {
// isActive: false,
isActive: true,
// isFirst: this.isFirst
};
},
computed: {
href() {
return this.formatHref(this.name);
},
},
mounted() {
this.selectTabFromURL();
},
methods: {
selectTabFromURL() {
let hash = this.$route.hash;
if (this.selected) {
this.isActive = this.selected;
} else if (!isEmpty(hash)) {
this.isActive = (this.formatHref(this.name) === hash);
} else if (this.isFirst) {
this.isActive = this.isFirst;
} else if (!this.isFirst && this.isActive) {
this.isActive = !this.isActive;
}
},
formatHref(id) {
return `#${id.toLowerCase().replace(/ /g, '-')}`;
}
}
}
</script>
the main component:
<template>
<!--components tabs start-->
<div class="flex flex-col">
<div class="mt-3 border-t-4 border-primary-color border-6 bg-white">
<div class=" border border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400 rounded-b lg:rounded-b-none lg:rounded-r leading-normal">
<Tabs #onTabChange="handleTabChange">
<!--:name="`${tab.name} - ${tab.component.type}`"-->
<Tab v-for="(tab, index) in page.tabs"
:key="tab.id"
:id="tab.slug"
:name="tab.name"
:slug="tab.slug"
:isFirst="index === 0"
>
<div>
How to render the dynamic accordion with the charts one time only no need to re-render
</div>
</Tab>
</Tabs>
</div>
</div>
</div>
<!--components tabs end-->
</template>
in normal HTML and JQuery, i can load the data and the render the result and append it to the wanted tab how can we do this with vue, dose the dynamic component help in this case ?
I searched for a solution and found and implement the "Creating Vue.js Component Instances Programmatically"
I'm trying to use quasar for the first time and I am trying to show a modal with a button but somehow the value won't turn to true which triggers my modal to show.
Home.vue
<template>
<div>
<q-layout>
<q-list highlight class="bg-white">
<q-list-header>Details
<q-btn color="green-5" #click="openAdd">Add New</q-btn>
</q-list-header>
<!-- <q-search/> -->
<q-item>
<q-item-side>
<q-item-tile avatar>
<img src="https://cdn.quasar.dev/logo/svg/quasar-logo.svg">
</q-item-tile>
</q-item-side>
<q-item-main label="John Doe" />
<q-item-side right>
<div>
<q-btn flat round icon="edit" color="yellow-8" small/>
<q-btn flat round icon="delete" color="red-8" small/>
<q-btn flat round icon="visibility" color="green-6" small/>
</div>
</q-item-side>
</q-item>
</q-list>
</q-layout>
<Add></Add>
</div>
</template>
Home.vue(script)
<script>
let Add = require('./Add.vue');
export default {
name: 'app',
components: {Add},
data(){
return{
addActive : ''
}
},
methods: {
openAdd() {
this.addActive = '';
}
}
}
</script>
Add.vue(modal):
<template>
<div>
<q-modal v-model="addActive" ref="layoutModal" :content-css="{minWidth: '50vw', minHeight: '50vh'}">
<q-modal-layout>
<q-toolbar slot="header" color="green-7">
<div class="q-toolbar-title">
Header
</div>
</q-toolbar>
<q-toolbar slot="footer" color="green-7">
<div class="q-toolbar-title">
Footer
</div>
<q-btn color="green-10" label="Save">Save</q-btn>
<q-btn color="red-9" #click="open = false" label="Close">Cancel</q-btn>
</q-toolbar>
</q-modal-layout>
</q-modal>
</div>
</template>
<script>
import {
QToolbar,
QToolbarTitle,
QBtn,
QModal,
QModalLayout
} from 'quasar-framework'
export default {
name: 'app',
components: {
QToolbar,
QToolbarTitle,
QBtn,
QModal,
QModalLayout
},
data() {
return {
layoutStore: {
view: 'lHh Lpr lFf',
reveal: false,
leftScroll: true,
rightScroll: true,
leftBreakpoint: 996,
rightBreakpoint: 1200,
hideTabs: false
}
}
},
data () {
return {
addActive: false
}
}
}
</script>
<style lang="stylus">
</style>
Any help is appreciated! Cheers and thanks!!
I tried turning the Add.vue's open value to return true and the modal shows up. But when I try to use the button to turn its value to true it does not work somehow.
You're defining
addActive as empty string in Home.vue
Have you tried
addActive: false (or true if you want it to open right away)
but you need to define in props as Boolean and pass those accordingly and not in data()