Vuetify adaptative grid layout from item list - vue.js

I have what seems to be a very common issue, but I can get over it.
I have an API query that returns me a list of object.
I want to display it my page as a grid of card filled with the content.
I want my grid to be in 5 column, and the number of row will adapt to the number of element in my list.
I can figure out how to achieve it.
For example: i have a query returning
items[
{"id":1,"title":"title1,"description":"description1"}
{"id":2,"title":"title2,"description":"description2"}
{"id":3,"title":"title3,"description":"description3"}
{"id":4,"title":"title4,"description":"description4"}
{"id":5,"title":"title5,"description":"description5"}
{"id":6,"title":"title6,"description":"description6"}
{"id":7,"title":"title7,"description":"description7"}
]
My grid as to be made from 7 elements with systematically 5 columns and adaptive rows like:
And if my query returns for example 14 elements, the layout should adapt to look like this:
The closest I was able to get with the code was.
<v-container class="mt-2">
<h1>Top Rated views</h1>
<v-row v-for="n in gridDivider" :key="n" class="n === 1 ? 'mb-6' : ''">
<v-col v-for="(item,index) in Items" :key="index">
<v-card class="mx-auto" max-width="300">
<v-img
class="white--text align-end"
height="200px"
src="item.avatar"
>
<v-card-title>anything as text</v-card-title>
</v-img>
<v-card-subtitle class="pb-0"> Number 10 </v-card-subtitle>
<v-card-text class="text--primary">
<div>Whitehaven Beach</div>
<div>Whitsunday Island, Whitsunday Islands</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
Thanks for helping

It could be done if you change v-row and v-col declarations this way:
<v-row class="five-cols">
<v-col v-for="(item,index) in Items" :key="index">
...
and create a CSS class five-cols using CSS Grid Layouts:
.five-cols {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
Example at CodePen

Related

Uniquely identify button click for individual v-cards in vuejs

I am using vuejs with vuetify 1.5 i am little bit stuck in my code the issue here is i have an array of objects and based on that multiple v-cards getting generated for all the values present in the array of objects.
In multiple cards i have a button expand so by default i want to show only 4 values and onclicking expand the rest of values will be shown in the cards and that expand button but the issue is all cards will have the same expand button so on clicking expand all cards are expanding and its values are shown but I want uniquely that means when i click expand only one cards value gets expanded rest of the cards will not expand.
here is my code :-
expandToggleHandler() {
this.isExpand = !this.isExpand
},
<v-card
style="display: inline-block;"
class="cardView"
:key="rowIndex"
#sort="onSort"
#click.native = "onRowClicked(row)"
>
<v-layout wrap>
<v-flex xs12 style="text-align: center; font-weight: bold;" :style="fixedColumn && clickableColumn || clickableColumn ? 'color: #ad00ff !important;' : 'color: #3399bb'">
{{row[Object.keys(row)[0]]}}
<br />
</v-flex>
</v-layout>
<v-layout wrap>
<template v-if="!isExpand">
<template v-for= "(key, idx) of cardViewColumn">
<template v-for="(col, i) of key">
<template v-if="idx <= 1">
<v-flex xs6 sm6 md6 style="text-align: center;">
<span style="font-weight: bold;">{{ col }}</span> <br /> {{row[col]}}
</v-flex>
</template>
</template>
</template>
</template>
<template v-if="isExpand">
<template v-for= "(key, idx) of cardViewColumn">
<template v-for="(col, i) of key">
<v-flex xs6 sm6 md6 style="text-align: center;">
<span style="font-weight: bold;">{{ col }}</span> <br /> {{row[col]}}
</v-flex>
</template>
</template>
</template>
<md-button #click.stop="expandToggleHandler">{{ toggleExpandAndCollapse }}</md-button>
</v-layout>
</v-card>
and here is the image :-
in image you can see i have pressed expand button for single cards but event is getting fired for other cards too.
How can i resolve it any help with example would be appreciated.
You are using the single variable isExpand for multiple v-card components. To solve your problem I suggest to convert the variable to an array and use rowIndex as the index.
Your variable declaration should look like this:
isExpand: []
Your templates would use it like this.
<template v-if="!isExpand[rowIndex]">
</template>
<template v-else>
</template>
Please note that I replaced the second v-if with a v-else so the isExpand variable isn't checked twice.
The method would become:
expandToggleHandler(rowIndex) {
this.isExpand[rowIndex] = !this.isExpand[rowIndex]
}
And you access it like this:
<md-button #click.stop="expandToggleHandler(rowIndex)">{{ isExpand[rowIndex] ? 'Collapse' : 'Expand'}}</md-button>
I didn't know what toggleExpandAndCollapse does but I guess it handles the button label.

Vuetify Two Images in Carousel-Item

All I want is to have a carousel-item that contains two images. At the very least I want two carousels side by side. Any ideas since wrapping the carousels in row-cols or simply trying a sheet containning two images in each carousel item does not work.
EDIT : Notice how the component surpasses the right edge of the app drawer (should not happen and also on transition the background of the carousel flashes black. Ideally I get a carousel that is responsive with the two images inside transitionning without flashing black.
<template>
<v-container>
<v-row>
<v-col cols="1">
<v-btn icon large #click="toggle">
<v-icon>{{ playIcon }}</v-icon>
</v-btn>
</v-col>
<v-col>
<v-slider
color="light-green"
thumb-color="light-green accent-4"
thumb-size="30"
track-color="light-green accent-4"
v-model="run"
max="19"
:tick-labels="ticksLabels"
tick-size="6"
ticks/>
</v-col>
</v-row>
<v-carousel
:cycle="playPause"
hide-delimiters
interval=3000
v-model="run"
height="700px"
hide-delimiter-background
show-arrows-on-hover
>
<v-carousel-item
transition="fade-transition"
reverse-transition="fade-transition"
v-for="(item,i) in items"
:key="i"
>
<v-row>
<v-card width="49%">
<v-img contain :src="item.avg"/>
</v-card>
<v-spacer></v-spacer>
<v-card width="49%">
<v-img contain :src="item.std"/>
</v-card>
</v-row>
</v-carousel-item>
</v-carousel>
</v-container>
</template>
You can fix the black flashing by adding these two props to the v-carousel
:dark="$vuetify.theme.dark"
:light="!$vuetify.theme.dark"
And to fix the scope of the component you can add this style.
<style scoped>
.v-carousel .v-window-item {
position: absolute;
top: 0;
width: 100%;
}
.v-carousel-item {
height: auto;
}
</style>

Adding Routes to Vuetify Buttons within v-cards?

This should be a simple fix but not sure where to start.
I have..
<template>
<div class="mx-5 mb-5 Weapons">
<h1 class="green--text">Weapons</h1>
<v-container class="my-5">
<v-layout row wrap>
<v-flex xs12 s6 m4 lg3 v-for="weapon in assaultrifles" :key="weapon.weapontype">
<v-card class="text-md-center ma-3 black">
<v-responsive class="pt-4">
<v-img contain :src="weapon.images"></v-img>
</v-responsive>
<v-card-title class="justify-center">
<div class="heading font-weight-black white--text">{{ weapon.WeaponType}}</div>
</v-card-title>
<v-card-actions class="justify-center">
<v-btn flat class="green black--text ma-3">View Weapons</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
I then have data in arrays with images and "titles" for these cards. I have about 8 cards , each representing its own "category" which is represented by the "title" data in my array.
What I am trying to do is make it so if I click on a card with the category/title "Handgun" or click on a card "rifle", I will be routed to a new page where I list out items for that specific category.. however I am not sure where to start because I am simply passing {{weapon.WeaponType}} into 1 card object, and then using 1 button ( with the text "view weapon"), across all the cards.
My understanding is that if I make a route for the 1 button I made, then the route will be the same for all buttons, despite the cards representing its own category, which would be bad because I don't want to see "handguns" when I click on the "shotgun" card’s button.
I want to somehow keep my current structure ( using 1 object and passing a loop of data ) and 1 btn, so that my code stays around the same length/structure).
Thanks for reading.
You will need additional property in your objects - for the route of the button:
<v-btn
flat
class="green black--text ma-3"
:to="weapon.route"
>
View Weapons
</v-btn>
The weapon.route can be a string or an object.
Another option is to provide just the category IDs and then
<v-btn
flat
class="green black--text ma-3"
:to="{name: 'weaponItems', params: {categoryID: weapon.categoryID}}"
>
View Weapons
</v-btn>

How can I remove shadow from expansion panel (Vuetify)?

I want to remove the shadow from a Vuetify expansion panel. Currently, it looks like this:
My code looks like this:
<v-layout wrap justify-space-between>
<v-flex xs12 pb-1>
<v-card>
<v-container pa-2>
<v-expansion-panel expand pa-0>
<v-expansion-panel-content>
<template v-slot:header>
<div>
{{ $t("var1") }}
</div>
</template>
<v-layout row wrap>
<v-flex xs12>
<v-text-field
class="right-input"
:label="$t('var2')"
value="600.00"
suffix="$"
disabled
flat
></v-text-field>
</v-flex>
</v-layout>
</v-expansion-panel-content>
</v-expansion-panel>
</v-container>
</v-card>
</v-flex>
</v-layout>
It is possible to remove the shadow from the expansion panel? I tried adding "flat" to the tag but it didn't solve it. My goal is that, while expanded, it looks like a flat card. Thanks! :)
In Vuetify v.2 you can use the attribute flat in v-expansion-panels.
Documented here: https://vuetifyjs.com/en/api/v-expansion-panels/#flat
<v-expansion-panels flat>
<v-expansion-panel >
<v-expansion-panel-header>
header
</v-expansion-panel-header>
<v-expansion-panel-content>
Content
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
You can set elevation-0 class on v-expansion-panel.
Here is working example: https://codepen.io/anon/pen/oKjRpm?editors=1010
I'd rather avoid changing CSS, because it will remove all borders and shadows, on all expansion panels on all pages.
With Veutify 2 the following css does the job.
.v-expansion-panel::before {
box-shadow: none !important;
}
Put this lines of code into your CSS:
.v-expansion-panel {
box-shadow: none;
}

How to display card components in loop with Vuetify grid system?

Note: Using Vue.js and Vuetify.js for functionality and styling
I have card components dynamically generated with v-for, and I want to display them in 1/3/4 card(s) in a row depending on screen size (sm/md/lg). When I place them in Vuetify's grid system, with v-flex and v-layout elements, the cards are minimized, instead of moving to the second row.
Is there another way to go about this?
<v-content>
<v-card class="d-inline-flex" v-for="company of companies" :key="company.name">
<v-layout >
<v-flex md6 lg6>
<img class="company-logo" src="../assets/img/example-logo.png" alt="company logo">
</v-flex>
<v-flex md6 lg6>
<v-card-title class="headline pl-0">{{company.name}}</v-card-title>
<article class="text-md-left text-lg-left">
<v-btn #click="selectDashboard(href('stats', company.name))" :value="company.name"><v-icon>local_offer</v-icon></v-btn>
<v-btn #click="selectDashboard(href('process', company.name))" :value="company.name"><v-icon>notifications</v-icon></v-btn>
<v-btn #click="selectDashboard(href('example', company.name))" :value="company.name"><v-icon>rate_review</v-icon></v-btn>
<v-btn #click="selectDashboard(href('alerts', company.name))" :value="company.name"><v-icon>explore</v-icon></v-btn>
<v-btn #click="selectDashboard(href('profile', company.name))" :value="company.name"><v-icon>room</v-icon></v-btn>
</article>
</v-flex>
</v-layout>
</v-card>
</v-content>
For a visual, this codepen shows the images width size decreases (but height size stays the same) - https://codepen.io/johnjleider/pen/aLXBez?editors=1111
The accepted answer did not work for me with v2 of Vuetify.
Now we can use <v-col> and you would do something like below.
<v-row>
<v-col cols="12" sm="3" md="4" v-for="(something, index) in somethingsArray" :key="index" >
<my-component :my-data="something" />
</v-col>
</v-row>
Where cols="12" is the same as xs="12" and the column would take up the full 12 spaces.
The sizing scales up starting with the smallest screens. Then on small screens each column would take up 4 spaces resulting in 3 columns and then for medium and larger screens use 3 spaces resulting in 4 columns.
|__|__|__|__|__|__|__|__|__|__|__|__| 12 spaces in the grid
|-----------------------------------| <-cols=12 (1 column)
|--------|--------|--------|--------| <-sm=3 (4 columns)
|-----------|-----------|-----------| <-md=4 and larger (3 columns)
The <v-flex> grid maxes out at 12. So if you set xs12 (extra small breakpoint) on the <v-flex xs12> it will take up all of the grid width until it hits the next breakpoint (If you don't set another breakpoint the lowest one will be applied to all screen widths). So then set <v-flex xs12 md6>, now when you hit the medium breakpoint each card will take up 6 grid spaces, which will allow you to have 2 cards side by side. Setting lg3, will allow you to fit 4 cards in the same space.
You can see it working in this modification to your example
https://codepen.io/twandy/pen/JrxamB?editors=1001