Vue show next 10 items when press button - vue.js

I'm trying to do load more function. When load more button is clicked show next 10 hidden items in v-for allCategories loop.
<template v-for="(category, i) in allCategories">
<v-col :key="i" v-show="i <= 10" class="col-6 col-sm-4">
<v-checkbox
dense
color="black"
:label="category.title"
:value="isCategoryChecked(category.id)"
#click="() => selectCategory(category.id)"
/>
</v-col>
</template>
load more button
<v-btn color="black white--text"
#click="showMoreCategories"
:loading="loading">
{{ $t('general.loadMore') }}
</v-btn>
showMoreCategories function
showMoreCategories() {
}
How do i implement this?

Assuming your variable allCategories contains all the categories you could possibly want (i.e. you don't have to fetch additional categories from a server or local store) then you can replace v-show="i <= 10" with v-show="i <= numberOfCategoriesToShow". Where numberOfCategoriesToShow is a new variable you have defined and initially set to 10.
Then your showMoreCategories function would look like this
showMoreCategories() {
this.numberOfCategoriesToShow += 10;
}

Related

Is there a way to toggle visibility for multiple password fields with a dynamic form using vuetify vuejs?

I have a dynamic form that is constructed based off of json from the backend of input types, id, names, values, etc. One of my forms has two password fields that come from the backend. Is there a way to toggle visibility for multiple password fields on the same dynamic form? I'm having trouble figuring out how to do this to one at a time. Right now, the toggle icon switches both password fields on the screen.
<template>
<div class="pb-4" >
<template v-for="formField in formFields">
<v-row
:key="formField.key"
dense
align="center"
>
<v-col
md="3"
class="font-weight-bold text-right pr-10"
align-self="center"
>
{{formField.name}}
<span v-if="formField.required" class="small"> *</span>
</v-col>
<v-col
md="8"
align-self="center"
class="pl-3"
>
<v-text-field
v-if="formField.type === 'password'"
:id="formField.key"
:key="formField.key"
v-model="formField.value"
:append-icon="showPasswordIcon ? '$vuetify.icons.values.eye' : '$vuetify.icons.values.eyeSlash'"
:type="showPasswordIcon ? 'text' : 'password'"
:hint="getHintText(formField)"
:value="formField.name"
:required="formField.required"
:valid="(!formField.isValid) ? false : undefined"
dense
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
#click:append="showPasswordIcon = !showPasswordIcon"
/>
<v-text-field
v-if="formField.type === 'text'"
:id="formField.key"
v-model="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
<v-checkbox
v-if="formField.type === 'boolean'"
:id="formField.key"
v-model="formField.value"
class="mt-2"
/>
<v-text-field
v-if="formField.type === 'number'"
:id="formField.key"
v-model.number="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
class="mb-0"
type="number"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
</v-col>
</v-row>
</template>
</div>
</template>
Thank you so much for any tips on this!
Easiest solution might be to add an extra property to each element in the formFields, like visible, that tracks if a password should show its text. You can do that on API response and then insert it.
Then in your loop you can do
:type="formField.visible ? 'text' : 'password'"
This way, every formField is responsible for their own password visibility.
Next, you change
#click:append="showPasswordIcon = !showPasswordIcon"
to
#click:append="toggleShowPassword(formField.key)"
toggleShowPassword(key){
let formfield = this.formfields.find(x => x.key === key)
if(formfield){
formfield.visible = !formfield.visible
}
}
That should work!

vuetify: why the table is sorted whenever the user clicks into the input field

I have a vuetify datatable, the original solution is dynamic allocation of search text field using v-for for each of the column and then multi filter is implemented. following is my solution:
<template v-for="(header, i) in columns" v-slot:[`header.${header.value}`]="{ }">
{{ header.text }}
<v-text-field :key="i"
v-model="multiSearch[header.value]"
class="pa"
type="text"
:placeholder="header.value"
prepend-inner-icon="mdi-magnify"
></v-text-field>
</template>
The problem is whenever an user clicks on the text field of a particular column, the sorting function also runs at the same time. I have a miniature solution on the following pen which has the same behaviour. I tried to put one div after template tag but still the same. Kindly have a look at it. Any help would be appreciated.
Code Pen
Wrap the text field with a DIV and attach an empty handler to prevent the bubbling of CLICK events:
<template v-for="(header, i) in columns" v-slot:[`header.${header.value}`]="{ }">
{{ header.text }}
<div #click.stop>
<v-text-field :key="i"
v-model="multiSearch[header.value]"
class="pa"
type="text"
:placeholder="header.value"
prepend-inner-icon="mdi-magnify"
></v-text-field>
</div>
</template>

How can I pass a v-data-table row information to child element

I have creating a list of users want to add them tags. I am using a data-table to display them and a combo box using chips to add or remove tags. How can I pass the user information to the method called when I add / remove a tag? Here is my code:
<v-data-table :headers="headers" :items="usersInfos" :search="search" :items-per-page="-1">
<template v-slot:[`item.tags`]="{ item }">
<v-combobox v-model="item.tags" :items="roles" chips clearable label="RĂ´les" multiple>
<template v-slot:selection="{ attrs, item, select, selected }">
<v-chip
v-bind="attrs"
:input-value="selected"
close
#click="select"
#click:close="removeRole(item)"
>
{{ item }} <!-- the tag -->
</v-chip>
</template>
</v-combobox>
</template>
</v-data-table>
Don't know if I understood it correctly but you can do following pass your item with your click event to your methods - call the function and use the passed parameter there.
in your template
#click=getSelectedItem(usersInfos)
in your script
methods: {
getSelectedItem(usersInfos) {
//do code here
console.log(usersInfos)
}
}
and than you have to use this where you have written your child element:
<child :usersInfo="usersInfo">
and in your child.vue you have to set props in your script like this:
props: ["usersInfo"]

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 Datatable - Rendering element on first row only

i have a problem on a vue project of mine.
i have a vuetify datatable that receives data from a .net core backend with mongo.
it works just fine and every row have a edit and delete buttons. but in this case i need to limit edit and delete buttons to show only on the first row of the datatable.
i've tried a lot of solutions from the internet but none of them worked for me so far.
here's the code for the datatable and the buttons, respectively:
<v-data-table
:headers="headers"
:items="pacientes"
:search="search"
:page.sync="page"
:items-per-page="itemsPerPage"
hide-default-footer
sort-by="status"
class="elevation-1"
#page-count="pageCount = $event"
>
<template
v-slot:item.edit="{ item }" >
<v-btn
color="blue"
tile
x-large
icon
#click="aprovar(item.nomePaciente, item.idEspera, item.matricula)"
>
<v-icon>mdi-pencil-circle</v-icon>
</v-btn>
</template>
<template
v-slot:item.delete="{ item }"
>
<v-btn
color="red"
x-large
tile
icon
#click="abrirModalDeletar(item.nomePaciente, item.idEspera)">
<v-icon>mdi-delete-circle</v-icon>
</v-btn>
</template>
Any help would be appreciated, thanks!
You could introduce a boolean property to your items in the array, let's call it isFirst Then you could listen to the event of current-items in the data table, which returns the current items in view. And based on that, show the buttons for the first row. So I suggest the following:
<v-data-table #current-items="setFirst" ...... >
And the function:
methods: {
setFirst: function(currItems) {
// first check that actually exists values
if (currItems.length) {
// toggle all to false
currItems.forEach(x => x.isFirst = false)
// just set first to true
currItems[0].isFirst = true;
}
}
},
and then set an v-if to the buttons:
<v-btn v-if="item.isFirst" ....>
CODEPEN
If your object has an ID and you know what that ID is, you can set a v-if statement for your edit and delete buttons to only render when the ID is equal to that value. Something like this:
<template
v-slot:item.edit="{ item }" >
<v-btn
color="blue"
tile
v-if="item.id===1"
x-large
icon
#click="aprovar(item.nomePaciente, item.idEspera, item.matricula)"
>
<v-icon>mdi-pencil-circle</v-icon>
</v-btn>
</template>
<template
v-slot:item.delete="{ item }"
>
<v-btn
color="red"
x-large
tile
v-if="item.id===1"
icon
#click="abrirModalDeletar(item.nomePaciente, item.idEspera)">
<v-icon>mdi-delete-circle</v-icon>
</v-btn>
</template>
If your item doesn't have an ID, when you fetch your data, you can programmatically set a property on the first item and then use the v-if statement on that property.
Something like:
fetchData().then(items => {
if (items.length >= 1) {
items[0].showEditDelete = true
}
})
Then your v-if statement will look like v-if=item.showEditDelete.