How to determine which q-expansion-item is open? - vue.js

I have a q-list with several q-expansion-items as children. The q-expansion-items are assigned to a list, so there is only one open at any given time.
<q-list padding>
<q-expansion-item
id="explore"
group="somegroup"
icon="explore"
label="Explore"
default-opened
#show="switchMode">
<q-card id="explore-card">
<q-card-section id="explore-card-section">
Item one text
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
id="identity"
group="somegroup"
icon="perm_identity"
label="Identity"
#show="switchMode">
<q-card>
<q-card-section>
Item two text.
</q-card-section>
</q-card>
</q-expansion-item>
</q-list>
I would like to run a Vue method when any q-expansion-item is opened and determine which specific item was opened.
I've tried assigning an id to each q-expansion-item, but need some clunky code to access the ID within the #show event: `
new Vue({
el: '#q-app',
data: function () {
return {}
},
methods: {
switchMode: function (event) {
console.log(event.target.parentElement.parentElement.parentElement.parentElement.id)
}
},
// ...etc
})
I've also tried using the to property to change the URL fragment, but that doesn't update the URL when the item is expanded (it only updates the URL fragment when clicking on the item title).
How can I determine which q-expansion-item in a group is open at any given time?

You can achieve this without using id's and events. You can use v-model instead.
Example -
<q-expansion-item
group="somegroup"
icon="explore" v-model="selected_model['First']"
label="First"
header-class="text-primary"
>
<q-card>
<q-card-section>
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</q-card-section>
</q-card>
</q-expansion-item>
<q-separator />
<q-expansion-item
group="somegroup"
v-model="selected_model['Second']"
icon="perm_identity"
label="Second"
header-class="text-teal"
>
<q-card>
<q-card-section>
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</q-card-section>
</q-card>
</q-expansion-item>
data -
data(){
return{
selected_model:{}
}
}
Result-
{ "First": true, "Second": false, "Third": false, "Fourth": false }
Codepen - https://codepen.io/Pratik__007/pen/poymOqm
and if you want First to open default then you can set "First":true in selected_model.

Related

Is it possible to change content of layout thought props?

I have that layout:
<template>
...navigation for all pages..
<h1>content for X??</h1>
<slot />
...footer for all pages...
</template>
For pages/index.vue:
<template>
index is here ok :)
</template>
and pages/about.vue:
<template>
about is here ok :)
</template>
I wish I could render h1 in layout for different pages and not print same text for all.
I know I can move h1 from layout to pages and edit each page.
But there are a lot of content between h1 and slot and I just want to change text.
There would be many ways of achieving what you are asking but the simplest would be the usage of named slots.
In the vue documentation (please take some time digging into it, the amount of deftail and explanation available is very appreciable) :
The <slot> element has a special attribute, name, which can be used to assign a unique ID to different slots so you can determine where content should be rendered.
The process of using named slots in the nuxt layouts is documented in the nuxt layout documentation.
You could create a TitleLayout.vue component in the layouts folder of your nuxt project that would look like this:
<!-- layouts/TitleLayout.vue -->
<template>
<div>
<nav>
<nuxt-link to="/"> index </nuxt-link>
<nuxt-link to="about"> about </nuxt-link>
</nav>
<main>
<h1>
<slot name="heading">
a default title
</slot>
</h1>
<slot/>
</main>
</div>
</template>
and that you could use it like this in your pages/About.vue (or in any other page)
<!-- pages/About.vue -->
<template>
<div>
<NuxtLayout name="with-title">
<template #heading> Hello from the about title </template>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quibusdam eius
rem, sit repellendus reiciendis explicabo? Dolorum totam molestias
adipisci cupiditate distinctio, libero dolorem iusto, quidem esse
excepturi voluptatem repellendus facere.
</NuxtLayout>
</div>
</template>
<script setup>
definePageMeta({
layout: false,
});
</script>

Carousel component from bootstrap-vue3 not working

I am creating Vue app with vue3 and using the bootstrap-vue3 package for Frontend.
I followed Bootstrap-Vue docs and copied the following code but Carousel doesn't work.
Of course, I can use another package for Carousel, but almost works already was done with this package. So I am looking for a solution to use this package.
Kindly let me know please if you folks how to fix this issue.
<template>
<div>
<b-carousel
id="carousel-1"
v-model="slide"
:interval="4000"
controls
indicators
background="#ababab"
img-width="1024"
img-height="480"
style="text-shadow: 1px 1px 2px #333;"
#sliding-start="onSlideStart"
#sliding-end="onSlideEnd"
>
<!-- Text slides with image -->
<b-carousel-slide
caption="First slide"
text="Nulla vitae elit libero, a pharetra augue mollis interdum."
img-src="https://picsum.photos/1024/480/?image=52"
></b-carousel-slide>
<!-- Slides with custom text -->
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=54">
<h1>Hello world!</h1>
</b-carousel-slide>
<!-- Slides with image only -->
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=58"></b-carousel-slide>
<!-- Slides with img slot -->
<!-- Note the classes .d-block and .img-fluid to prevent browser default image alignment -->
<b-carousel-slide>
<template #img>
<img
class="d-block img-fluid w-100"
width="1024"
height="480"
src="https://picsum.photos/1024/480/?image=55"
alt="image slot"
>
</template>
</b-carousel-slide>
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eros felis, tincidunt
a tincidunt eget, convallis vel est. Ut pellentesque ut lacus vel interdum.
</p>
</b-carousel-slide>
</b-carousel>
<p class="mt-4">
Slide #: {{ slide }}<br>
Sliding: {{ sliding }}
</p>
</div>
</template>
<script>
export default {
data() {
return {
slide: 0,
sliding: null
}
},
methods: {
onSlideStart(slide) {
this.sliding = true
},
onSlideEnd(slide) {
this.sliding = false
}
}
}
</script>
You need a active prop in any one of the b-carousel-slide tag to display the slide.
It is something not mentioned in the documentation.

How to customize image size for card in vue bootstrap

I am working on a NuxtJS project, with BootstrapVue as front-end framework. I am trying to edit the size of an image inserted inside the title of a card, with the following code:
<b-card
bg-variant="primary"
text-variant="white"
img-alt="Image"
img-src="~/assets/images/house.png"
header="The house"
class="text-center position-relative"
>
<b-card-text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</b-card-text>
<b-button variant="primary" class="paragraph stretched-link"
>Click here</b-button
>
</b-card>
Does anyone know if is possible to customize the style of the image through the b-card properties (without CSS)? The documentation did not helped me.
You could use img-height and img-width to provide the image size inside the card, they accepts a string or a number as values :
<b-card
bg-variant="primary"
text-variant="white"
img-alt="Image"
img-src="~/assets/images/house.png"
img-height="200"
img-width="200"
header="The house"
class="text-center position-relative"
>

Vue Event listener on mouse hold

How can you set a boolean to true when the mouse click is held down, and false when you release the click? On Vue I am using v-on:mousedown="hold = !hold" But this toggles the boolean instead of having the user hold the click down.
You need to use the events mousedown and mouseup. Try something like this:
<template>
<div>
<div :style="{ 'background-color': color }">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
</div>
<button #mousedown="color = 'orange'" #mouseup="color = 'green'" >Click here</button>
</div>
</template>
<script>
export default {
name: 'App',
data: () => ({
color: 'yellow',
}),
};
</script>
Use both mousedown and mouseup events.
<div
v-on:mousedown="hold = true"
v-on:mouseup="hold = false"
>{{hold}}</div>

How can we show multiple items with Bootstrap-Vue Carousel?

I think boostrap-vue carousel not so detailed. For this reason i can't reach to nice solution.
I wanna just show 3 items (like in image) in my app and i didnt find the solution and i searched other package and there was no solution for me.
All i want to do like this;
data() {
return {
slide: 0,
sliding: null
};
},
methods: {
onSlideStart(slide) {
this.sliding = true;
},
onSlideEnd(slide) {
this.sliding = false;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div>
<b-carousel id="carousel-1" v-model="slide" :interval="0" controls indicators background="white" img-width="650" img-height="480" #sliding-start="onSlideStart" #sliding-end="onSlideEnd">
<b-carousel-slide caption="First slide" text="Nulla vitae elit libero, a pharetra augue mollis interdum." img-src="https://picsum.photos/1024/480/?image=52"></b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=54">
<h1>Hello world!</h1>
</b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=58"></b-carousel-slide>
<b-carousel-slide>
<img slot="img" class="d-block img-fluid w-100" width="1024" height="480" src="https://picsum.photos/1024/480/?image=55" alt="image slot">
</b-carousel-slide>
</b-carousel>
<p class="mt-4">
Slide #: {{ slide }}<br> Sliding: {{ sliding }}
</p>
</div>
If you have any other library suggestion i would appreciate.
Thanks for help.
BootstrapVue <b-carousel> is designed to only show a single slide at a time (as is the standard bootstrap V4.x carousel component). There are never more than 2 slides visible at once (during the slide or fade transition, all other slides are hidden. CSS transforms are used to make the appearance of the slides moving)
You would need to either find a 3rd party component that supports multiple slides showing, or generate your own custom component.
I'm not familiar with this specific component, but this is from its documentation:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eros felis, tincidunt
a tincidunt eget, convallis vel est. Ut pellentesque ut lacus vel interdum.
</p>
</b-carousel-slide>
I would try using a blank image as the default and inserting whatever other images/content you want as children of the slide:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<img class="my-img" src="img1.jpg"/>
<img class="my-img" src="img2.jpg"/>
<img class="my-img" src="img3.jpg"/>
</b-carousel-slide>
And use absolute positioning or flexbox to display them the way you want.
I did the same thing using b-card-group. Because b-carousel does not support showing multiple items.
In template area
<div>
<!-- carousel area -->
<b-card-group deck class="mb-0">
<b-card v-for="(item,index) in currentPageCards" :key="index" class="mr-0">
<!-- card content -->
</b-card>
</b-card-group>
<!-- pagination area -->
<div class="pagination" v-if="cards.length>cardsPerPage">
<div class="index" v-for="i in pageCount" :key="i" #click="next(i)" :class={active:currentPage(i)}></div>
</div>
</div>
In script area
data() {
return {
cards: [{
//Data in the card as objects
},{},{},{},{}],
paginatedCards:[],
pageCount:0,
cardsPerPage:4,
currentPageIndex:0
}
},
computed: {
currentPageCards(){
this.createPages();
return this.paginatedCards[this.currentPageIndex];
}
},
methods:{
currentPage(i){
return i-1===this.currentPageIndex;
},
createPages() {
let cardsLength = this.cards.length;
let fullPagesCount = Math.floor(cardsLength/this.cardsPerPage);
if(cardsLength>this.cardsPerPage) {
this.pageCount = 0;
for (let i = 0; i < fullPagesCount * this.cardsPerPage; i += this.cardsPerPage) {
this.paginatedCards[this.pageCount] = this.cards.slice(i,i + this.cardsPerPage);
this.pageCount++;
}
this.paginatedCards[this.pageCount] = this.cards.slice(cardsLength-this.cardsPerPage,cardsLength);
this.pageCount = this.pageCount+1;
} else {
this.paginatedCards[0] = this.cards;
}
},
next(i){
this.currentPageIndex=i-1;
}
}
In style area
.pagination{
display:flex;
align-items: center;
justify-content: center;
padding:10px;
}
.index{
margin-left:10px;
width:10px;
height:10px;
background:#000000
}
.active{
width:15px;
height:15px;
}
It shows like as below
Try this one. Thank you!