What am I missing about the vuetify grid-system? - vue.js

I am having issues with getting the vuetify grid-system to work properly. I have installed vuetify, added it as a plugin to my app and imported it into my file. When I use its <v-container> or <v-row>- tags, a grid shows up, so that should all be working. What is not working however, is the "linking" of columns to rows. I believe that I have the code set up correctly, as it is basically a copy of the tutorial-code on the vuetify website. When I run the file, the columns are children of the rows, as expected, but are shown below eachother, not next to eachother. I have two rows which I do expect to be shown below eachother, but I want the columns of each row to be shown horizontally to eachother, inside the row.
Here is how I want it to look like, it is a screenshot of an example from the vuetify docs:
What I end up with however, looks like this:
I will also provide my code here:
<template>
<v-container class="grey lighten-5">
<v-row
v-for="n in 2"
:key="n"
:class="n === 1 ? 'mb-6' : ''"
no-gutters>
<v-col
v-for="k in n + 1"
:key="k">
<v-card
class="pa-2"
outlined
tile>
{{ k }} of {{ n + 1 }}
</v-card>
</v-col>
</v-row>
</v-container>
</template>
I really hope someone can help me, as I am very stuck and feel like I have tried everything.
I appreciate every answer! :)
EDIT: I just saw that the console tells me that "[Vue warn]: Unknown custom element: <v-col> - did you register the component correctly? For recursive components, make sure to provide the "name" option.". That seems strage to me, as there are indeed rows and columns shown on the rendered site. Does anyone have an idea on how to tackle this issue?

Related

How to cache filtered out elements to prevent re-rendering inside a v-for?

I’ve been working on a Vue.js application that manages user’s notes and allows to easily look them up by title, tags, etc. So the primary view of a logged-in user is a list view of Card components. I’m using v-lazy and group-transition components to enhance usability. Everything works fine, but…
When the set of notes becomes larger (100+ Cards), one can notice (especially on mobile devices) that filtering slows down. After some debugging I found that the filtering calculations are not the heavy part but the re-rendering of filtered components is the real problem.
Let’s say, with the following scenario:
there's a list of 150 Card components
the user scrolled down to the end of the page, so that 150 Cards are in fact rendered and one of them contains tag: tag-1
if the user clicks on tag-1, 149 Cards get filered out, the 1 result
remains Vvue debug tool shows that 149 Card components get destroyed as the computed method visibleCards contains only one element)
if the user unclicks the tag-1, all 149 Cards are re-rendered again
(Vue debug tool shows that 149 Cards are fully re-created again)
Below, there’s the meat of my Card list displaying view:
<v-row justify="center" dense class="px-sm-2">
<transition-group
name="list"
tag="div"
class="cardListTransition col-12 pa-0"
>
<v-row
:id="'columnid-' + index"
v-for="(card, index) in visibleCards"
:key="card.id + ':' + card.created"
justify="center"
class="snipSingleRow"
>
<v-col lg="10" xl="8" class="pt-0 mb-lg-4 mb-xl-4">
<v-sheet min-height="50" class="fill-height" color="transparent">
<!-- 'threshold: indicates at what percentage of the target's visibility -->
<!-- the observer's callback should be executed. -->
<v-lazy
v-model="card.active"
:options="{
threshold: 0.8,
}"
class="fill-height"
transition="list"
>
<Card :card="card" />
</v-lazy>
</v-sheet>
</v-col>
</v-row>
</transition-group>
</v-row>
where: visibleCards is a result of a computed method inside of which filtering occurs.
Is there any way - I’ve experimented with v-once or keep-alive, etc. with no help - to save / cache the filtered out components to prevent them from re-rendering once the filters are cleared?
PS.
Stripping down the list i.e. removing v-lazy or group-transition doesn’t solve the problem.
I’d appreciate any help / suggestions or further reading on how to solve my problem.

Use fallback content of slot only if condition is met

I would like to know if there is a way to do what I'm trying to describe below:
Let's suppose we have a component with a slot, and a fallback content has been defined.
When using this component elsewhere, I would like to have the following behavior:
<TheComponent>
<template v-slot:name="{ data }">
<fallback v-if="condition(data)"/>
</template>
</TheComponent>
I suppose the fallback tag (or similar) does not exists (at least, I didn't find it...). So I suppose I'm thinking the wrong way, but I can't find a solution to my problem.
The thing is that I can't alter the TheComponent as it is provided by an external library, and I don't want to re-create the content.
If it can help, in fact, I'm trying to hide the expand button to prevent to expand a row in a Vuetify data-table, depending on if the row has something to show or not in it's expanded part. So I would like to write something that behave like:
<v-data-table :items="items" show-expand ...>
<template v-slot:item.data-table-expand="{ item }">
<!-- Here I want the default behavior only if my item respects some condition -->
<fallback v-if="condition(item)"/>
<!-- Otherwise, I don't want to display the button that expands the row -->
</template>
</v-data-table>
Thank you in advance for your help.
After quite a lot of "googling" I don't think its possible. IMHO your best bet is to replicate the default slot content Vuetify generates and put it under your own condition (v-if="item.description" in my example):
<v-data-table :headers="headers" :items="people" show-expand>
<template v-slot:expanded-item="{ item, headers }">
<td :colspan="headers.length">{{ item.description }}</td>
</template>
<template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
<v-icon
v-if="item.description"
:class="['v-data-table__expand-icon', { 'v-data-table__expand-icon--active': isExpanded }]"
#click.stop="expand(!isExpanded)"
>$expand</v-icon>
</template>
</v-data-table>
I understand this solution is brittle and can break anytime Vuetify change something but i don't think there is better solution now...
Example

bootstrap-vue toggle expand table row

This seems to remain unanswered so here is another attempt at a solution.
Currently in bootstrap-vue, I am rendering a b-table. I would like to improve this by having the ability to select a row and collapse/expand an extra div/row/etc to show further information.
In the below snippet you will see what I am trying. The problem is that I can't seem to get the expanded data to span the number of columns in the table. I have tried adding <tr><td colspan="6"></td></tr> but it doesn't seem to span like I would expect. Any workarounds for this? Thanks.
<b-table
:items="case.cases"
:fields="tableFields"
head-variant="dark">
<template
slot="meta.status"
slot-scope="data">
<b-badge
v-b-toggle.collapse1
:variant="foobar"
tag="h6">
{{ data.value }}
</b-badge>
</template>
<template
slot="#id"
slot-scope="data">
<span
v-b-toggle.collapse1>
{{ data.value }}
</span>
<b-collapse id="collapse1">
Collapse contents Here
</b-collapse>
</template>
</b-table>`
Sounds like you could use the Row Details slot:
If you would optionally like to display additional record information (such as columns not specified in the fields definition array), you can use the scoped slot row-details
<b-table :items="case.cases" :fields="tableFields" head-variant="dark">
<template slot="meta.status" slot-scope="data">
<b-button #click="data.toggleDetails">
{{ data.value }}
</b-button>
</template>
<template slot="row-details" slot-scope="data">
<b-button #click="data.toggleDetails">
{{ data.detailsShowing ? 'Hide' : 'Show'}} Details }}
</b-button>
<div>
Details for row go here.
data.item contains the row's (item) record data
{{ data.item }}
</div>
</template>
</b-table>
There is a good example in the docs at https://bootstrap-vue.js.org/docs/components/table#row-details-support
I (think) I had the same issue, and I came up with a solution which leverages the filtering functionality of the bootstrap-vue <b-table> to achieve the effect of expanding and collapsing rows.
There's a minimal example in a JSFiddle here:
https://jsfiddle.net/adlaws/mk4128dg/
Basically you provide a tree structure for the table like this:
[
{
columnA: 'John', columnB:'Smith', columnC:'75',
children:
[
{ columnA: 'Mary', columnB:'Symes', columnC:'46' },
{ columnA: 'Stan', columnB:'Jones', columnC:'42' },
{ columnA: 'Pat', columnB:'Black', columnC:'38' },
]
}
]
The tree is then "flattened" out to rows which can be displayed in a table by the _flattenTreeStructure() method. During this process, the rows are also annotated with some extra properties to uniquely identify the row, store the depth of the row (used for indentation), the parent row of the row (if any) and whether or not the row is currently expanded.
Once this is done, the flattened structure can be handed to the <b-table> as it is just an array of rows - this is done via the computed property flattenedTree.
The main work now is done by the _filterFunction() method which provides custom filtering on the table. It works off the state of the expandedRowIndices property of the filterObj data item.
As the expand/collapse buttons are clicked, the row index (as populated during the flattening process) is inserted as a key into expandedRowIndices with a true or false indicating its current expanded state.
The _filterFunction() uses this to "filter out" rows which are not expanded, which results in the effect of expanding/collapsing a tree in the table.
OK, so it works (yay!), but...
it's not as flexible as the base <b-table>; if you want to show different columns of data, you'll need to do some work and to re-do the <template slot="???"> sections for the columns as required.
if you want to actually use filtering to filter the content (with a text search, for example) you'll need to extend the custom filter function to take this into account as well
sorting the data is not something I had to do for my use case, and I'm not sure how it would work in the context of a tree structure anyway - maintaining the tree's parent/child relationships while changing the order of the rows around would be... fun, and I suspect this would be a nice challenge to implement for someone who is not as time poor as me. ;)
Anyway, I hope this is of use to someone. I'm reasonably new to Vue.js, so there may be a better way to approach this, but it's done the job I needed to get done.

Flexible layout with hide/show of panel

We want to set up a UI like this, where A cards are shown by default, and if needed B shows on the right side:
Before:
┌────────────────────┐
│┌───┐┌───┐┌───┐┌───┐│
││A ││A ││A ││A ││
│└───┘└───┘└───┘└───┘│
└────────────────────┘
After:
┌────────────────┐┌──┐
│┌──┐┌──┐┌──┐┌──┐││ │
││A ││A ││A ││A │││B │
│└──┘└──┘└──┘└──┘││ │
└────────────────┘└──┘
So note in the beginning, the container for the A cards take up the full width, then when B shows, the A cards shrink a bit in width, and B takes up about 1/6 of the width.
This is how v-container, v-layout, v-flex etc. are set up right now:
<v-container fluid>
<v-layout>
<v-flex>
<v-card>
<v-container fluid grid-list-xl>
<v-layout row wrap>
<v-flex xs6 sm4 md3 lg2 xl1 v-for="record in records" :key="record.id">
<v-card flat tile>
<!-- "A" code -->
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-card>
</v-flex>
<v-flex v-show="showPanel">
<v-card>
<!-- "B" code -->
</v-card>
</v-flex>
</v-layout>
</v-container>
The way the code runs now is that it shows "Before" okay, but for "After" it shows just a thin column for B like 1/12 of the width of the screen, and the As squeeze in just a bit. Anything I do to change the width of B just screws up the layout completely, like takes 50% of the width, or has As showing in three or fewer columns instead of four.
I think my structure might be fundamentally wrong, but I'm having a hard time wrapping my head around how v-container, v-layout, and v-flex are supposed to work, and the documentation is not helpful.
Confirmed it was the fluid in the line <v-container fluid grid-list-xl> that was causing troubles. Once I removed it, layout was as expected. The problem couldn't be duplicated in CodePen likely because the template was rendered in another environment with its own layout rules, so whatever conflict there was showed up only in that context.

Vue js , How to target a data object if the name needs to be concatanated based on a variable

I am really struggling to find an answer for my use case, but I have been stuck for hours, and also unable to find a similar question in StackOverflow.
Here is a part of my code :
<v-tabs-items>
<v-tab-item
v-for="i in stepnumber"
:id="'tab-' + i"
:key="i"
>
<v-list two-line>
<div id="dropdown-example" class="minheight1">
<v-list-tile v-for="(item, index) in 'tabcomputed' + i" :key="item.id">
The tabscomputed1, tabscomputed2, etc. exist as data inside Vue, but I cannot find the proper syntax to target this data when I need to concat the tabscomputed with the variable i inside the v-for loop.
Thanks in advance.
you could use $data["tabscomputed"+i]
Here is a codesandbox link, check out App.vue