Showing table heading once in VueJS component - vue.js

I have a search built in VueJS and the results of the search are displayed in a separate component. I want to display the data in a table with the table headings. The issue I'm having is that the table heading appears before each row. How do I get it to appear once? Im sure this is easy but I cant think how to do this. Im fairly new to Vue, so any help appreciated.
<table class="table table-hover" id="simpleTable">
<thead>
<tr>
<th
v-on:click="sortTable(title)"
:key="title"
scope="col"
class="col-md-3"
>
Course
</th>
<div
class="arcoursedata"
v-if="title == sorttitle"
v-bind:class="ascending ? 'arcoursedata_up' : 'arcoursedata_down'"
></div>
<th scope="col">Award</th>
<th scope="col">Level</th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-md-3">
{{ title }}
</td>
<td>
{{ award }}
</td>
<td class="col-md-3">
{{ level }}
</td>
<td class="col-md-3">
<a
:href="result.displayUrl"
class="btn-sm btn-primary"
role="button"
>
<span class="sr-only">Read more about {{ title }}</span> Read
more</a
>
</td>
</tr>
</tbody>
</table>

You need to separate row from tbody to component. And do v-for only on this component and not on the entire table.
It will be look like:
<table class="table table-hover" id="simpleTable">
<thead>
<tr>
<th
v-on:click="sortTable(title)"
:key="title"
scope="col"
class="col-md-3"
>
Course
</th>
<div
class="arcoursedata"
v-if="title == sorttitle"
v-bind:class="ascending ? 'arcoursedata_up' : 'arcoursedata_down'"
></div>
<th scope="col">Award</th>
<th scope="col">Level</th>
</tr>
</thead>
<tbody>
<rowComponent v-for="rowData in tableData" :row="rowData"></rowComponent>
</tbody>
</table>
And RowComponent will look like:
<td class="col-md-3">
{{ row.title }}
</td>
<td>
{{ row.award }}
</td>
<td class="col-md-3">
{{ row.level }}
</td>
<td class="col-md-3">
<a :href="row.displayUrl"
class="btn-sm btn-primary"
role="button">
<span class="sr-only">Read more about {{ row.title }}</span> Read
more</a>
</td>
<script>
export default {
name: "rowComponent",
props: ['row']
}
</script>

Related

How to refactor this table with Vue?

I have a table where I have 6 rows and 4 columns that looks like this
`
<template>
<div class="col-md-12">
<fieldset>
<legend>Sellers Data Comparison</legend>
<div class="row">
<div class="col-xs-12">
<table class="table table-condensed" id="SellersDataComparisonTable">
<thead>
<tr>
<th>
<h4></h4>
</th>
<th class="numeric">Sellers Data</th>
<th class="numeric">Asset Index</th>
<th class="numeric">Deviation</th>
</tr>
</thead>
<tbody>
<tr>
<td><label># Accounts</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.NumberOfAccounts,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.AssetIndex.NumberOfAccounts,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.NumberOfAccounts ,'0,0') }}
</td>
</tr>
<tr>
<td><label># Customers</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.NumberOfCustomers,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.AssetIndex.NumberOfCustomers,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.NumberOfCustomers,'0,0') }}
</td>
</tr>
<tr>
<td><label>Principal</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.Principal,'0,0.00') }}
</td>
<td class="numeric">
{{useFormatNumber( store.assetIndexSummary?.SellersDataComparison.AssetIndex.Principal,'0,0.00') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.Principal,'0,0.00') }}
</td>
</tr>
<tr>
<td><label>Face Value</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.FaceValue,'0,0.00') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.AssetIndex.FaceValue,'0,0.00') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.FaceValue,'0,0.00') }}
</td>
</tr>
<tr>
<td><label>L12 payers</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.NumberOfPayersInLast12M,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.AssetIndex.NumberOfPayersInLast12M,'0,0') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.NumberOfPayersInLast12M,'0,0') }}
</td>
</tr>
<tr>
<td><label>L12 avg payment</label></td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.LatestSellersData.AveragePaymentsinLast12M,'0,0.00') }}
</td>
<td class="numeric">
{{useFormatNumber( store.assetIndexSummary?.SellersDataComparison.AssetIndex.AveragePaymentsinLast12M,'0,0.00') }}
</td>
<td class="numeric">
{{ useFormatNumber(store.assetIndexSummary?.SellersDataComparison.Deviation.AveragePaymentsinLast12M,'0,0.00') }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</fieldset>
</div>
</template>
`
As you can see it is very copy paste and clunky, I am trying to make it reusable and more elegant with vue.js, here is the problem I have the data for each column is coming from a different source - LatestSellersData, AssetIndex and Deviation.
What I tried was making a TableRow.Vue component that looks like this
<template>
<tr>
<td><label>{{ label }}</label></td>
<td class="numeric">{{ useFormatNumber(itemValue) }}</td>
<td class="numeric">{{ useFormatNumber(itemValue) }}</td>
<td class="numeric">{{ useFormatNumber(itemValue) }}</td>
</tr>
</template>
<script lang="ts">
import { defineComponent, inject } from 'vue';
import useFormatNumber from '#/use/formatNumber';
export default defineComponent({
props: {
label: String,
itemValue: Number,
},
setup() {
return {
useFormatNumber
};
}
})
</script>
The problem with this is the table data would look like this because I need to be putting value in to columns not rows
AssetIndex
Latest Data
Deviation
Number of People
1
1
1
Value
2
2
2
Average value
3
3
3
What I want it to look like is this
AssetIndex
Latest Data
Deviation
Number of People
1
2
3
Value
1
2
3
Average value
1
2
3
Hope I made my problem clear, thanks in advance!

Is Vue 3 backwards compatible with Vue 2?

In different posts around the internet (for example this one) I found that Vue 2 code should work with Vue 3 but for me it does not. For example I have simple component
<template>
<div class="overflow-x-auto bg-white rounded-lg shadow overflow-y-auto relative">
<table class="table">
<thead>
<tr class="text-left">
<th>
<label>
<input type="checkbox">
</label>
</th>
<th>User ID</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>Gender</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label>
<input type="checkbox" name="1">
</label>
</td>
<td> <span>{{ id }}</span> </td>
<td> <span>Cort</span> </td>
<td> <span>Tosh</span> </td>
<td> <span>{{ email }}</span> </td>
<td> <span>Male</span> </td>
<td> <span>327-626-5542</span> </td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
id: 1,
email: 'test#mail.com'
}
},
mounted() {
alert('mounted');
},
created() {
alert('created');
}
};
</script>
The table is generated just fine, but both mounted and created not fired when component made. Also the email and id not shown. Only the table is shown.
Your code works:
Vue.createApp({
data() {
return {
id: 1,
email: 'test#mail.com'
}
},
created() {
alert('created')
},
mounted() {
alert('mounted')
}
}).mount('#app')
<script src="https://unpkg.com/vue#next"></script>
<div id="app" class="overflow-x-auto bg-white rounded-lg shadow overflow-y-auto relative">
<table class="table">
<thead>
<tr class="text-left">
<th>
<label>
<input type="checkbox">
</label>
</th>
<th>User ID</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th>Gender</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label>
<input type="checkbox" name="1">
</label>
</td>
<td> <span>{{ id }}</span> </td>
<td> <span>Cort</span> </td>
<td> <span>Tosh</span> </td>
<td> <span>{{ email }}</span> </td>
<td> <span>Male</span> </td>
<td> <span>327-626-5542</span> </td>
</tr>
</tbody>
</table>
</div>

How To Make A Loop Using v-for With Condition "Like Forelse" In Laravel Framework

I'm Just Trying To Do Something using Vue Similar To forelse in laravel framework blade,
This Is Just To Do a Test To Confirm If Table Has Records Or Not, If No, It Allows Me To Add A Default Value Like :
<tr>
<td colspan="4">There's No Records Yet</td>
</tr>
I Tried This But It Gives Me [vue/no-use-v-if-with-v-for]
<tr v-for="(category, index) in this.categories" :key="index" v-if="categories">
<td>{{ category.id }}</td>
<td>{{ category.name }}</td>
<td style="width: 20%;">
<img :src="`${$store.state.baseUrl}/storage/${category.image}`" style="width: 100%;" :alt="category.name">
</td>
<td>
<button type="button" class="btn btn-danger" #click="deleteCategory(category)"><i class="fa fa-trash"></i></button>
<i class="fa fa-edit"></i>
</td>
</tr>
<tr v-else>
<th colspan="4" class="text-center">There's No Reacoards Yet</th>
</tr>
Is There Anyone Has A Solution For This Issue,
Thank You
- Muhammed Elfeqy
This is one of the times where you want to use the invisible <template> element
For example
<template v-if="categories.length > 0">
<tr v-for="category in categories" :key="category.id">
<!-- and so on -->
</tr>
</template>
<tr v-else>
<td colspan="4">There's No Records Yet</td>
</tr>

Vuejs - reading data from table

I'm trying to pull an updated value out of the table below to send it to database, but it appears that Vue does not support two-way data binding. Could anyone give me a hint on how I extract the current cell value and pass it to a function saving new data to a database?
<table v-if="tableData.length > 0" class="table table-bordered table-sm">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Date From</th>
<th scope="col">Date To</th>
<th scope="col">Days</th>
<th scope="col">Type</th>
<th scope="col">Request Date</th>
</tr>
</thead>
<tbody>
<tr v-for="(object, index) in tableData" :key="index">
<th scope="=row"><label class="tableNumberColumn">{{index + 1}}</label></th>
<td #change="readData" v-for="(value, key) in object" :key="key" v-if="key != 'formId'">
<div #change="readData" class="container tableColumnDiv" v-if="key === 'numberOfDays'" contenteditable="true">{{value}}</div>
<div class="container tableColumnDiv" v-else-if="key === 'timeOffType'" contenteditable="true">{{value}}</div>
<div v-else>
<datepicker :value="value" :bootstrap-styling="true"></datepicker>
</div>
</td>
<td>
<b-button #click="deleteRow(index)" class="btn btn-sm buttonDelete">Delete</b-button>
</td>
<td>
<b-button #click="update(index)" class="btn btn-sm buttonUpdate">Update</b-button>
</td>
<td>
<b-button class="btn btn-sm buttonPrint">Print</b-button>
</td>
</tr>
</tbody>
I am pasting the code one more time as I've removed some unnecessary stuff:
<table v-if="tableData.length > 0" class="table table-bordered table-sm">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Date From</th>
<th scope="col">Date To</th>
<th scope="col">Days</th>
<th scope="col">Type</th>
<th scope="col">Request Date</th>
</tr>
</thead>
<tbody>
<tr v-for="(object, index) in tableData" :key="index">
<th scope="=row"><label class="tableNumberColumn">{{index + 1}}</label></th>
<td v-for="(value, key) in object" :key="key" v-if="key != 'formId'">
<div class="container tableColumnDiv" v-if="key === 'numberOfDays'" contenteditable="true">{{value}}</div>
<div class="container tableColumnDiv" v-else-if="key === 'timeOffType'" contenteditable="true">{{value}}</div>
<div v-else>
<datepicker :value="value" :bootstrap-styling="true"></datepicker>
</div>
</td>
<td>
<b-button #click="deleteRow(index)" class="btn btn-sm buttonDelete">Delete</b-button>
</td>
<td>
<b-button #click="update(index)" class="btn btn-sm buttonUpdate">Update</b-button>
</td>
<td>
<b-button class="btn btn-sm buttonPrint">Print</b-button>
</td>
</tr>
</tbody>

Style slot in vue

Have a Table call in Index.vue:
<utilization-table :title="table.title" :columns="table.columns" :rows="table.rows">
<template scope="data>
<td class="th_normal">{{data.row.name}}</td>
</template>
</utilization-table>
The Table Template is UtilizationTable.vue:
<template>
<div>
<h3 v-html="title"></h3>
<table class="table table-striped table-hover">
<thead>
<tr>
<th v-if="selectable" class="table-view-pf-select" aria-label="Select all rows">
<label>
<span class="sr-only">Select all rows</span>
<input type="checkbox" #change="changeSelectAll">
</label>
</th>
<th v-for="column in columns">{{column}}</th>
</tr>
</thead>
<tbody>
<utilization-table-row ref="row" v-for="(row, i) in rows" :key="i">
<slot :row="row"></slot>
</utilization-table-row>
</tbody>
</table>
</div>
</template>
With a Row as UtilizationTableRow.vue:
<template>
<tr role="row">
<slot></slot>
</tr>
</template>
It'd like to style the first "td" in the table to 130px. Since it is a slot, I'm not sure how to do this.
Normally, if my table is
<table>
<tr>
<td>
</td>
</tr>
</table>
I could just do:
<style> table tr td:first-child, table tr td:first-child {
width: 130px !important;
}
</style>
However, that isn't taking hold.