bootstrap vue get row data when click on cell in custom rendering - vue.js

I have a table that have two custom fields index and a trash icon in separate column for remove that row. I want to get row's in click on just trash icon (on cell) for get index of row and then remove it from items in data object but my problem is I don't know how to get row data in onclick event in custom rendering. How can I do that??
<b-table :fields="fields" :items="items">
<template v-slot:cell(index)="data">
{{ data.index + 1 }}
</template>
<template v-slot:cell(remove)="data">
<i class="fas fa-trash"></i>
</template>
</b-table>
this is my data:
fields: [
{ key: 'index', label: 'index' },
{ key: 'cardNumber',label: 'card number'},
{ key: 'status',label: 'status'},
{ key: 'remove',label: 'remove'}
],
items: [
{ cardNumber: '123456', status: 'accepted' ,_cellVariants: { status: 'accepted-card-number'},_showDetails: true},
{ cardNumber: '123456', status: 'pending' ,_cellVariants: { status: 'pending-card-number'},_showDetails: true},
{ cardNumber: '123456', status: 'unaccepted' ,_cellVariants: { status: 'unAccepted-card-number'},_showDetails: true},
],

This should be what your looking for https://jsfiddle.net/q95otzbg/. You just need a click function on your trash icon passing it the index of the row.
<div id="app">
<div>
<b-table :fields="fields" :items="items">
<template v-slot:cell(index)="data">
{{ data.index + 1 }}
</template>
<template v-slot:cell(remove)="data">
<i class="fas fa-trash" #click=removeRow(data.index)></i>
</template>
</b-table>
</div>
</div>
methods: {
removeRow(index) {
this.items.splice(index,1)
}
}

Related

Boostrap modal renders multiple times

In my Table component, I'm using Vue Bootstrap's b-table component to create a table, which retrieves its' data from an external JSON file through Vuex. Now I also have another component, Actions, which is rendered on each row of the table. This component contains an edit button which is supposed to open a modal when clicked.
The problem is that whenever I click the edit button, 4 modals come up one on top of another. The issue seems to lie in the number of rows rendered, because in the JSON file, there are 4 objects, each of which contains the student's name, date of birth and so on. When I get rid of three of these objects, the modal only renders once. My conclusion is that the modal is rendering 4 times, for each row, but I have no idea how to fix this.
Here's the Table and Actions component:
<script>
import Actions from "./Actions.vue"
export default {
data() {
return {
fields: [
'index',
'full_name',
{ key: "date_of_birth", label: 'Date of Birth' },
'municipality',
{ key: "action", label: 'Action' }
],
// tableItems: this.$store.state.registeredStudents.registeredStudents
}
},
components: {
Actions
},
methods: {
generateIndex() {
return Math.floor(1000000 * Math.random()).toString().slice(0, 6);
}
},
computed: {
rows() {
return this.tableItems.length
},
tableItems() {
const registeredStudents = this.$store.state.registeredStudents.registeredStudents
return registeredStudents.map(student => ({
index: this.generateIndex(), ...student
}))
}
},
}
</script>
<template>
<b-table :fields="fields" :items="tableItems" :per-page="perPage" :current-page="currentPage" responsive="sm" primary-key="index"
striped hover>
<template #cell(action)="data">
<Actions/>
</template>
</b-table>
</template>
<script>
import { BIconPencilFill, BIconTrashFill } from 'bootstrap-vue';
export default {
}
</script>
<template>
<div>
<b-button variant="primary" class="mx-1 p-1" v-b-modal.edit-student>
<b-icon-pencil-fill></b-icon-pencil-fill>
</b-button>
<b-modal id="edit-student" title="Edit student info">
<p class="my-4">Hello from modal!</p>
</b-modal>
<b-button variant="danger" class="mx-1 p-1">
<b-icon-trash-fill></b-icon-trash-fill>
</b-button>
</div>
</template>
The problem here is most likely because your id's are not unique. For each row of your table you are generating the following;
<b-modal id="edit-student" title="Edit student info">
<p class="my-4">Hello from modal!</p>
</b-modal>
with the same ID.
I think the best approach here would be to include the Actions in the Table component. You don't need the extra component since it has no internal logic or props.
Table.vue
data() {
return {
fields: [
'index',
'full_name',
{ key: "date_of_birth", label: 'Date of Birth' },
'municipality',
{ key: "action", label: 'Action' }
],
lastClickedRowIndex: -1
}
},
...
<template>
<b-table :fields="fields" :items="tableItems" :per-page="perPage" :current-page="currentPage" responsive="sm" primary-key="index"
striped hover>
<template #cell(action)="data">
<b-button variant="primary" class="mx-1 p-1" #click="() => (lastClickedRowIndex = data.index)" v-b-modal.edit-student>
<b-icon-pencil-fill></b-icon-pencil-fill>
</b-button>
<b-button variant="danger" class="mx-1 p-1">
<b-icon-trash-fill></b-icon-trash-fill>
</b-button>
</template>
</b-table>
<b-modal id="edit-student" title="Edit student info">
<p class="my-4">Hello from modal!</p>
<!-- Dynamically change contents here based on lastClickedRowIndex -->
</b-modal>
</template>
I apologise if any syntax is incorrect I've only used Vue 3.

Vuetify table - add hyperlink to column

In my vue component I am using vuetify table. It works properly, but I need to make that click on items in column "Category name" redirect to vue view which shows details of clicked item (I need to forward item id to view which shows details of item). I don`t know how to do that?
In method 'editItem' I also need to redirect to other page, with forwarded id, I also don`t know how to do that?
I tried to make "Category name" items as hyperlink, but it does not work and it is without id:
<template v-slot:item.categoryName="{ item }">
<a :href="this.$router.push({name: 'EditCategory'})">{{item.categoryName}}</a>
</template>
This is code of my vue component 'CategoryTable':
<template>
<v-data-table
:headers="headers"
:items="categories"
sort-by="categoryName"
class="elevation-1"
:footer-props="{
'items-per-page-options': [1, 2, 3, 4, 5]
}"
:items-per-page="2"
>
<template v-slot:top>
<v-toolbar
flat
>
<v-toolbar-title>Categories Table</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<button #click="$router.push({name: 'AddCategory'})">Add category</button>
</v-toolbar>
</template>
<template v-slot:item.actions="{ item }">
<v-icon
small
class="mr-2"
#click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
#click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
</v-data-table>
</template>
<script>
export default {
name: "CategoriesTable",
data: () => ({
headers: [
{
text: 'Category name',
align: 'start',
value: 'categoryName',
},
{ text: 'Description', value: 'description' },
{ text: 'Actions', value: 'actions', sortable: false },
],
categories: [],
editedIndex: -1,
defaultItem: {
id: 0,
categoryName: '',
description: '',
},
}),
created () {
this.initialize()
},
methods: {
initialize () {
this.$axios.get('/api/categories').then((response) => {
console.log(response.data)
this.categories = response.data;
});
},
editItem (item) {
this.$router.push({name: 'CategoryEdit'});
item.id
},
deleteItem (item) {
this.$axios.delete('/api/categories/' + item.id).then((response) => {
console.log(response)
});
},
},
}
</script>
If you want the user to be redirected after clicking on a particular category name, you will pass the corresponding route or id like i did below:
<v-data-table
:headers="headers"
:items="categories"
sort-by="categoryName"
class="elevation-1"
:footer-props="{
'items-per-page-options': [1, 2, 3, 4, 5],
}"
:items-per-page="2"
>
<template v-slot:item.categoryName="{ item }">
<a
#click="$router.push(`/details/${item.itemID}`)"
>
{{item.categoryName}}
</a>
</template>
</v-data-table>
the item id is passed after clicking on the category

add hyperlink in v-data-table Vuetify

I've been slowly learning the joys of vue.js and Vuetify.
I'm trying to get the emails and website as working links but just can't figure out how to do it.
I have my v-data-table
<v-data-table :headers="headers" :items="companies" :search.sync="search" :items-per-page="5">
In my script I'm having first:
data: () => ({
headers: [
{ text: "Bedrijfsnaam", align: "start", value: "name" },
{ text: "Telefoon", value: "phone" },
{ text: "e-Mail", value: "email" },
{ text: "Website", value: "website" },
{ text: "Locatie", value: "location" },
{ text: "Actions", value: "actions", sortable: false }
],
companies: [],
}),
And finally
methods: {
initialize() {
this.companies = [
{
name: "Lorem NV",
phone: "+32 1 234 56 78",
email: "info#lorem.be",
website: "www.lorem.be",
location: "Gent"
},
];
}
Welcome to Stack Overflow!
You need to implement a custom template for the row that has the link:
<v-data-table
:headers="headers"
:items="companies"
:search.sync="search"
:items-per-page="5"
>
<template #item.phone="{ item }">
<a target="_blank" :href="`tel:${item.phone}`">
{{ item.phone }}
</a>
</template>
<template #item.email="{ item }">
<a target="_blank" :href="`mailto:${item.email}`">
{{ item.email }}
</a>
</template>
<template #item.website="{ item }">
<a target="_blank" :href="item.website">
{{ item.website }}
</a>
</template>
</v-data-table>
You can put whatever content inside of the <template> elements that you want, so, for example, if you had an id field for each company and you wanted to link the company name to the page within your website that has the details page about that company, you could do:
<v-data-table
:headers="headers"
:items="companies"
:search.sync="search"
:items-per-page="5"
>
<template #item.name="{ item }">
<router-link :to="{ name: 'company', params: { id: item.id } }">
{{ item.name }}
</router-link>
</template>
</v-data-table>
You can put buttons, icons, or whatever you want inside of the template. Hope this helps!
You can use the item.<name> slot. For example, where website is the property name:
<template #item.website="{ value }">
<a :href="value">
{{ value }}
</a>
</template>
OR email,
<template #item.email="{ value }">
<a :href="`mailto:${value}`">
{{ value }}
</a>
</template>
This only needs to be used for the fields you want to customize.
Demo: https://codeply.com/p/CX3vXv6x6R

Vue-bootstrap - when table changes items, buttons do not seem be to updated

I started using vue-bootstrap to generate a table with items. One of the columns "actions" contains button to show, edit and enable/disable the item (changing active property to true/false) based on item ID.
When I disable an item (click the button disable), the table is updated and does not show it anymore, however it looks like the buttons (show/edit/disable/enable) for that particular item stop working (e.g. not able to enable the project back or to edit it). Also the first item in the table does not have the buttons functional.
Item example:
{ id: '1', key: 'key1', name: 'name1', description: 'description1', active: 'true' }
Any idea what could be wrong?
<b-row class="mb-3">
<b-col cols="12">
<b-navbar type="light" variant="light">
<b-nav-form>
<i class="fas fa-search mr-3"></i>
<b-input-group>
<b-form-input v-model="filter" id="filterInput" placeholder="Search" ></b-form-input>
<b-input-group-append>
<b-button :disabled="!filter" #click="filter = ''" class="mr-sm-3">Clear</b-button>
</b-input-group-append>
</b-input-group>
<b-form-checkbox v-model="archivedChecked" size="sm">
Archived
</b-form-checkbox>
</b-nav-form>
</b-navbar>
</b-col>
</b-row>
<b-row>
<b-col cols="12">
<b-table bordered hover head-variant="dark" :filter="filter" :items="filteredProjects" :fields="fields">
<template v-slot:cell(actions)="row">
<b-button-group>
<b-button size="sm" variant="info" :to="'/msd/' + row.item.key" title="Show">Show</b-button>
<b-button v-b-modal="'edit-project-' + row.item.id" size="sm" variant="outline-info" :title="'Edit ' + row.item.name">
<i class="far fa-edit"></i>
</b-button>
<b-button v-if="!archivedChecked" v-b-modal="'disable-project-' + row.item.id" size="sm" variant="outline-secondary" title="Archive">
<i class="fas fa-archive"></i>
</b-button>
<b-button v-if="archivedChecked" v-b-modal="'enable-project-' + row.item.id" size="sm" variant="outline-secondary" title="Restore">
<i class="fas fa-trash-restore"></i>
</b-button>
<edit-project-modal :modal_id="'edit-project-' + row.item.id" :id="row.item.id" />
<disable-project-modal :modal_id="'disable-project-' + row.item.id" :id="row.item.id"/>
<enable-project-modal :modal_id="'enable-project-' + row.item.id" :id="row.item.id"/>
</b-button-group>
</template>
</b-table>
</b-col>
</b-row>
</div>
</template>
<script>
import EditProject from '~/components/modal/EditProject.vue'
import DisableProject from '~/components/modal/DisableProject.vue'
import EnableProject from '~/components/modal/EnableProject.vue'
import { mapGetters } from 'vuex'
export default {
layout: 'IncludeSidebar',
data() {
return {
fields: [
{
key: 'key',
sortable: false
},
{
key: 'name',
sortable: true
},
{
key: 'description',
sortable: true
},
{
key: 'actions',
sortable: false
}
],
archivedChecked: false,
filter: null
}
},
computed: {
loadedProjects() {
return this.$store.getters.loadedProjects;
},
filteredProjects() {
if (this.archivedChecked) {
return this.loadedProjects.filter(item => item.active === false)
} else {
return this.loadedProjects.filter(item => item.active === true)
}
}
},
methods: {
},
components: {
NewProjectModal: NewProject,
EditProjectModal: EditProject,
DisableProjectModal: DisableProject,
EnableProjectModal: EnableProject
}
}
</script>
Instead of calling the modals directly from buttons, I moved the trigger to a method and it solved the issue.
<b-button v-if="row.item.active" #click="showModal('disable-project-' + row.item.id)" size="sm" variant="outline-secondary" title="Archive">
methods: {
showModal(type, modal_id) {
this.$root.$emit('bv::show::modal', modal_id);
}
}

bootstrap-vue datatable show row details issue

trying to achieve the same result as https://bootstrap-vue.js.org/docs/components/table#row-details-support
My code:
<b-table ref="propertydata" striped hover
:items="datatable.items"
:fields="datatable.fields"
:current-page="datatable.currentPage"
:per-page="datatable.perPage"
:filter="datatable.filter"
:sort-by.sync="datatable.sortBy"
:sort-desc.sync="datatable.sortDesc"
:sort-direction="datatable.sortDirection"
#filtered="onFiltered">
<template slot="action" slot-scope="row">
<!-- we use #click.stop here to prevent emitting of a 'row-clicked' event -->
<b-button size="sm" #click.stop="row.toggleDetails" class="mr-2">
{{ row.detailsShowing ? 'Hide' : 'Show'}} Details
</b-button>
</template>
<template slot="row-details" slot-scope="row">
<b-card>
<ul>
<li v-for="(value, key) in row.item" :key="key">{{ key }}: {{ value}}</li>
</ul>
</b-card>
</template>
</b-table>
<b-row>
<b-col md="6" class="my-1">
<b-pagination :total-rows="datatable.totalRows" :per-page="datatable.perPage" v-model="datatable.currentPage" class="my-0" />
</b-col>
</b-row>
/* Datatable related */
datatable: {
fields: [
{
key: 'account_id',
sortable: true
},
{
key: 'account_name',
sortable: true
},
{
key: 'property_count',
sortable: true,
},
{
key: 'commission',
sortable: true,
variant: 'success'
},
{
key: 'action',
}
],
items: [],
currentPage: 1,
perPage: 20,
totalRows: 0,
pageOptions: [ 20, 100, 300, 500, 1000, 2000, 3000 ],
sortBy: null,
sortDesc: false,
sortDirection: 'asc',
filter: null
}
computed: {
sortOptions () {
// Create an options list from our fields
return this.datatable.fields
.filter(f => f.sortable)
.map(f => { return { text: f.label, value: f.key } })
}
}, // END COMPUTED
methods: {
onFiltered (filteredItems) {
// Trigger pagination to update the number of buttons/pages due to filtering
this.datatable.totalRows = filteredItems.length
this.datatable.currentPage = 1
}
}, // END METHODS
The result is:
As you can see, the show details is isolated to a single column instead of the full row.
What I want to achieve is for this show details section to be the full row width and if I could click the button to go to a method to call additional data to be displayed here as oppose to the native bootstrap-vue functionality.