add an icon next to each row in the table using bootstrap vue? - vue.js

I have a table that uses bootstrap Vue's table. Each row of the table corresponds to an item. My current problem is I need to add an icon next to each row, and display them every time I hover over that row, and then do some function when I click on this icon. But I can't find a way to add an icon. I have tried following the instructions on https://bootstrap-vue.org/docs/components/table with using slots but it only works for #head and #cell. Need an idea on this issue. This is my code and a picture describe my problem
<b-table
ref="table"
class="minh--30 mh--100 overflow-y-auto"
bordered
responsive
:items="items"
:fields="fields"
>
<template #head()="data">
<span>{{ $t(data.field.label) }}</span>
</template>
<template #cell(field)="data">
<span
v-if="data.item.isDrag"
class="d-block p-3"
>{{ data.item.field }}</span>
<b-dropdown
v-else
right
no-caret
variant="white"
class="minw--40 w-100"
menu-class="w-100 mh--24 overflow-auto minw-unset"
>
<template #button-content>
<div
class="flex-center minh--11 text-normal position-relative px-2"
>
<span class="pr-5 word-break text-line-clamp-1">{{ data.item.field }}</span>
<i
class="fas fa-chevron-down position-absolute top-50 end--1 translate-middle-y px-2"
/>
</div>
</template>
<b-dropdown-item
v-for="item in listField"
:key="item.id"
variant="normal py-2"
class="fs-12 fs-xl-15"
#click="selectField(item, data)"
>
<span class="word-break text-line-clamp-1">{{ $t(item.text) }}</span>
</b-dropdown-item>
</b-dropdown>
</template>
<template #cell(action)="data">
<b-dropdown
right
no-caret
variant="white"
class="minw--40 w-100"
menu-class="w-100 mh--24 overflow-auto minw-unset"
>
<template #button-content>
<div
class="flex-center minh--11 text-normal position-relative px-2"
>
<span class="pr-5 word-break text-line-clamp-1">{{ data.item.action }}</span>
<i
class="fas fa-chevron-down position-absolute top-50 end--1 translate-middle-y px-2"
/>
</div>
</template>
<b-dropdown-item
v-for="item in listDropdown"
:key="item.id"
variant="normal py-2"
class="fs-12 fs-xl-15"
#click="selectItem(item, data)"
>
<span class="word-break text-line-clamp-1">{{ $t(item.text) }}</span>
</b-dropdown-item>
</b-dropdown>
</template>
<template #cell(selectCharacter)="data">
<b-dropdown
right
no-caret
variant="white"
class="minw--40 w-100"
menu-class="w-100 mh--24 overflow-auto minw-unset"
>
<template #button-content>
<div
class="flex-center minh--11 text-normal position-relative px-2"
>
<span class="pr-5 word-break text-line-clamp-1">{{ data.item.selectCharacter }}</span>
<i
class="fas fa-chevron-down position-absolute top-50 end--1 translate-middle-y px-2"
/>
</div>
</template>
<b-dropdown-item
v-for="item in listCharacter"
:key="item.id"
variant="normal py-2"
class="fs-12 fs-xl-15"
#click="selectCharacter(item, data)"
>
<span class="word-break text-line-clamp-1">{{ $t(item.text) }}</span>
</b-dropdown-item>
</b-dropdown>
</template>
<template #cell(inputCharacter)="data">
<input
v-model="data.item.inputCharacter"
type="text"
class="form-control h--11 border-0"
>
</template>
<template #cell(startPosition)="data">
<input
v-model="data.item.startPosition"
type="number"
class="form-control h--11 border-0"
>
</template>
<template #cell(characterCount)="data">
<input
v-model="data.item.characterCount"
type="number"
class="form-control h--11 border-0"
>
</template>
<template #cell(needReplace)="data">
<input
v-model="data.item.needReplace"
type="text"
class="form-control h--11 border-0"
>
</template>
<template #cell(replace)="data">
<input
v-model="data.item.replace"
type="text"
class="form-control h--11 border-0"
>
</template>
<template #cell(delete)="data">
<div class="flex-center pt-1">
<input
v-if="!data.item.isDrag"
v-model="data.item.delete"
type="checkbox"
>
</div>
</template>
</b-table>

Based on reading the documentation, the table component wasn't designed for this use case because you are adding icons that are outside of the table itself.
One alternative would be to use the grid system https://bootstrap-vue.org/docs/components/layout#layout-and-grid-system to create one narrow column on the left for the icons and one wide column on the right for the table. In the narrow column, you could create rows that are exactly the height of each row of the table so that the items stay aligned with each row.
Another alternative would be to use the #cell slot, and put an element inside that uses CSS, possibly the transform property (https://www.w3schools.com/cssref/css3_pr_transform.asp), to make the element appear to the left of where it really is.

Related

How do I get a div to overflow and not extend the page using flex box?

Here is my code:
<template>
<div class="main-column d-flex flex-column h-100">
<div class="pl-3 pr-3">
<filter-panel ref="filterComp" :controls="filterControls" :urlParams="$route.query" #filterResults="onSearchClicked" />
</div>
<div class="flex-grow-1 d-flex flex-column px-1 py-2 bg-container">
<div class="position-relative h-100">
<div class="absoluteFill">
<div class="collapse-panel nested-background mb-2 w-100">
<div class="collapse-bar full-length">
<b-button class="buttonRow w-100 py-0 d-flex justify-content-between" size="sm" variant="link" #click="hideGraphs = !hideGraphs" v-b-toggle.count-collapse>
<span class="title">Chart</span>
<icon :class="{'down': hideGraphs}" class="icon rotate mt-1" icon="chevron-up" size="lg" />
</b-button>
</div>
<b-collapse id="count-collapse" visible>
<transition name="fade" mode="out-in">
<div>
<DxChart :data-source="graphData"
palette="Material"
class="p-3">
<DxCommonSeriesSettings type="bar" argument-field="date">
<DxLabel>
<DxFormat :precision="0" type="fixedPoint" />
</DxLabel>
</DxCommonSeriesSettings>
<DxSize :height="350" />
<DxSeries name="Mapping Client"
value-field="mappingClient"
color="#a4de02" />
<DxSeries name="Mapping ISCI"
value-field="mappingIsci"
color="#add8e6" />
<DxSeries name="Mapping Product"
value-field="mappingProduct"
color="#ff0000" />
<DxLegend :visible="true" />
<DxTooltip :enabled="true" />
</DxChart>
</div>
</transition>
</b-collapse>
</div>
<!--Grid card-->
<div class="collapse-panel nested-background mb-2 d-flex flex-column w-100 ">
<div class="collapse-bar full-length">
<b-button class="buttonRow w-100 py-0 d-flex justify-content-between" size="sm" variant="link" #click="hideGrids = !hideGrids" v-b-toggle.counts-collapse>
<span class="title">Grids</span>
<icon :class="{'down': hideGrids}" class="icon rotate mt-1" icon="chevron-up" size="lg" />
</b-button>
</div>
<b-collapse id="counts-collapse" visible>
<transition name="fade" mode="out-in">
<dx-tab-panel ref="tabPanel" :items="tabs">
<div slot="title" class="wordwrap" slot-scope="tab">{{tab.data.title}}</div>
<div slot="item" slot-scope="tab">
<span v-if="isTab(tab, 0)">
<data-summary :graphData="graphData"></data-summary>
</span>
<span v-if="isTab(tab, 1)"><user-data :rawData="rawData"></user-data></span>
</div>
</dx-tab-panel>
</transition>
</b-collapse>
</div>
</div>
</div>
</div>
</div>
I need the last table to have an overflow inside the div and not scroll the page. I also need that div to expand if the chart is minimized. I have been trying to solve this all day I'm out of answers, I feel like this should be a super simple fix but I just can't get it.
Thanks for any help!

Bootstrap Vue b-table displaying nested object

I'm trying to list the drivers in b-table.
This gives me the correct name of the driver:
console.log(this.orders[0].order_drivers[0].populated_driver.user.username)
But when I want to display it on the table, it gives "data.item.order_drivers[0] is not defined" error.
Here's my code:
<b-table :items="orders"
:fields="fields"
:per-page="perPage"
:current-page="currentPage"
:filter="filter"
:filter-function="filterDate"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
sort-icon-left
small
>
<template #cell(status)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.status }}</span>
</div>
</template>
<template #cell(order_number)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.order_number}}</span>
</div>
</template>
<template #cell(deliver_date)="data">
<span class="align-text-top text-capitalize">{{ data.item.deliver_date }}</span>
</template>
<template #cell(pickup_date)="data">
<span class="align-text-top text-capitalize">{{ data.item.pickup_date }}</span>
</template>
<template #cell(subtotal)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.subtotal }}</span>
</div>
</template>
<template #cell(tip)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.tip_from_restaurant }}</span>
</div>
</template>
<template #cell(additional_tip)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.extra_tip_from_restaurant }}</span>
</div>
</template>
<template #cell(tfr_tip)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.tip_from_tfr }}</span>
</div>
</template>
<template #cell(tfr_additional_tip)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.extra_tip_from_tfr }}</span>
</div>
</template>
<template #cell(driver)="data">
<div class="text-nowrap">
<span class="align-text-top text-capitalize">{{ data.item.order_drivers[0].populated_driver.user.username}}</span>
</div>
</template>
</b-table>
And this is what axios returns:
Response
UPDATE:
I've added v-if and v-else as suggested and worked for me!
<div class="text-nowrap">
<span class="align-text-top text-capitalize" v-if="orders[data.index].order_drivers.length!==0" >{{ data.item.order_drivers[0].populated_driver.user.username}}</span>
<span class="align-text-top text-capitalize" v-else>None.</span>
</div>

how to display data from props in b-table template tag?

i am new in vue.js and get some problem while displaying data in b-table. my data from database is fetched properly. and i passed from one file to products.vue and received data in products.vue as props. when i console my data is showing in console properly, but when i used to display data in b-table, i got some problem. data is not displaying correctly.
please let me know where is mistake in my code?
Products.vue (script tag)
<script>
export default {
props: ['category','singular', 'plural','products'],
data() {
return {
title: `All ${this.plural}`,
items: [],
editing: false,
weight_assignment: false,
model: null,
formTitle: '',
fields: [
{
key: 'index',
label: 'S.No.'
},
{
key: 'name',
sortable: true
},
{
key: 'weights'
},
{
key: 'default_weight',
sortable: true
},
{
key: 'status',
sortable: true
},
{
key: 'action'
}
],
}
</script>
Product.vue (template tag)
<template>
<div class="row">
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">{{title}}</h3>
<div class="card-tools">
<b-button variant="primary" #click="newItem">New {{singular}}</b-button>
<div></div>
</div>
</div>
<div class="card-body table-responsive p-0">
<spinner v-if="$root.loading"></spinner>
<b-table ref="table" v-for="type in this.products" :items="type" :key="type.id" :fields="fields" bordered hover :head-variant="'light'" responsive="sm" v-else>
<template v-slot:cell(index)="type">
{{ type.index + 1 }}
</template>
<template v-slot:cell(name)="type">
<b-img thumbnail fluid :src="getImageUrl(type.image)" alt="Image 1" class="thumb-img"></b-img>
{{type.name}}
</template>
<template v-slot:cell(weights)="type">
<span v-weights="type.item"></span>
</template>
<template v-slot:cell(default_weight)="type">
<span v-floatFormatter="type.default_weight"></span>{{type.unit.sname}}
</template>
<template v-slot:cell(status)="type">
<span v-if="type.status" class="text-success text-bold">Active</span>
<span class="text-danger" v-else>Inactive</span>
</template>
<template v-slot:cell(action)="data">
<a #click.prevent="editItem(data.index)"><i class="fa fa-edit" aria-hidden="true" title="Update product" v-b-tooltip.hover></i></a>
<a #click.prevent="assignWeights(data.index)"><i class="fa fa-balance-scale" title="Assign weights" aria-hidden="true" v-b-tooltip.hover></i></a>
</template>
</b-table>
</div>
</div>
</div>
</div>
</template>
v-for="type in this.products" - try to delete this key. In template tag do not use this keyword to access data or any other values.
I have spotted you pass data completely wrong way. Please use below variant and tell me if it work.
EDITED template:
<template>
<div class="row">
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">{{title}}</h3>
<div class="card-tools">
<b-button variant="primary" #click="newItem">New {{singular}}</b-button>
<div></div>
</div>
</div>
<div class="card-body table-responsive p-0">
<spinner v-if="$root.loading"></spinner>
<b-table ref="table" :items="products" :fields="fields" bordered hover :head-variant="'light'" responsive="sm" v-else>
<template v-slot:cell(index)="data">
{{ data.index + 1 }}
</template>
<template v-slot:cell(name)="data">
<b-img thumbnail fluid :src="getImageUrl(data.image)" alt="Image 1" class="thumb-img"></b-img>
{{data.name}}
</template>
<template v-slot:cell(weights)="data">
<span v-weights="data.item"></span>
</template>
<template v-slot:cell(default_weight)="data">
<span v-floatFormatter="data.default_weight"></span>{{data.unit.sname}}
</template>
<template v-slot:cell(status)="data">
<span v-if="data.status" class="text-success text-bold">Active</span>
<span class="text-danger" v-else>Inactive</span>
</template>
<template v-slot:cell(action)="data">
<a #click.prevent="editItem(data.index)"><i class="fa fa-edit" aria-hidden="true" title="Update product" v-b-tooltip.hover></i></a>
<a #click.prevent="assignWeights(data.index)"><i class="fa fa-balance-scale" title="Assign weights" aria-hidden="true" v-b-tooltip.hover></i></a>
</template>
</b-table>
</div>
</div>
</div>
</template>
I tried a lot, after all this, my code is working correctly now, this given below code is the right solution.
<b-table ref="table" :items="products" :fields="fields" bordered hover :head-variant="'light'" responsive="sm" v-else>
<template v-slot:cell(index)="data">
{{ data.index+1 }}
</template>
<template v-slot:cell(name)="data">
<b-img thumbnail fluid :src="getImageUrl(data.item.image)" alt="Image 1" class="thumb-img"></b-img>
{{data.item.name}}
</template>
<template v-slot:cell(weights)="data">
<span v-weights="data.item"></span>
</template>
<template v-slot:cell(default_weight)="data">
<span v-floatFormatter="data.item.default_weight"></span>{{data.item.unit.sname}}
</template>
<template v-slot:cell(status)="data">
<span v-if="data.status" class="text-success text-bold">Active</span>
<span class="text-danger" v-else>Inactive</span>
</template>
<template v-slot:cell(action)="data">
<a #click.prevent="editItem(data.item.id)"><i class="fa fa-edit" aria-hidden="true" title="Update product" v-b-tooltip.hover></i></a>
<a #click.prevent="assignWeights(data.item.id)"><i class="fa fa-balance-scale" title="Assign weights" aria-hidden="true" v-b-tooltip.hover></i></a>
</template>
</b-table>

v-if="this.canupdate == true" not working

In vue I have a property this.canupdate.
My code looks like
<template v-if="this.canupdate == true">
<template v-if="row.item.edit">
<b-button variant="success" size="sm" #click="saveprestatierij(row.item, row.index)">
<i class="fas fa-save"></i>
</b-button>
</template>
<template v-else>
<b-button variant="primary" size="sm" #click="toggleeditprestatierij(row.item)">
<i class="fas fa-edit"></i>
</b-button>
</template>
</template>
But when I run the code, the block is not displaying, even if this.canupdate has a true value.
Anybody who sees where I'm wrong?
Kind regards,
Tim
Remove this from if-statement:
<template v-if="canupdate === true">
Or you can write like this:
<template v-if="canupdate">

How to detect wheter search input focused or not in vue-instantsearch?

In my component Search.vue I need to detect whether search input focused or not in order to hide search results if cursor is elsewhere
I used vue-instantsearch
Here is the code of my custome component's template section
<template>
<ais-index index-name="getstarted_actors" :search-store="searchStore">
<div class="col-md-10 col-sm-9">
<ais-search-box :autofocus="true">
<div class="input-group" ref="searchInputGroup">
<ais-input placeholder="Find books..."
:class-names="{'ais-input': 'form-control'}" autofocus="true" >
</ais-input>
<span class="input-group-btn">
<ais-clear :class-names="{'ais-clear': 'btn btn-default'}">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</ais-clear>
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
</span>
</div>
</ais-search-box>
<ais-results v-show="searchStore.query.length > 0">
<template scope="{ result }">
<div v-on:click="searchResultClick(result)" class="found-item">
<a> <span>{{ result.name }}</span> <span>{{ result.rating }}</span></a><br/>
</div>
</template>
</ais-results>
</div>
</ais-index>
</template>
You can try:
<ais-input placeholder="Find books..."
:class-names="{'ais-input': 'form-control'}" autofocus="true"
#focus="onFocus"
>
</ais-input>
and your methods:
methods: {
onFocus() { console.log('Focused') }
}