Add style to first row of v-data-table in vuetify - css

I have defined the table as below using vuetify data table component. The issue I am facing here is I not able to figure out how can I make the first row of the table bold. The first item record to be bold. Please help find a solution.
I am using vuetify 1.0.5.
<v-data-table>
:headers="headers"
:items="agents"
hide-actions
class="agent-table"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td>{{ props.item.address }}</td>
</template>
</v-data-table>

use v-if to search for first row index or something unique about first row and bind it to style or class. Few more ways listed here reference
<template slot="items" slot-scope="props">
<tr v-if="unique condition" v-bind:style="{ 'font-weight': 'bold'}>
<td>{{ props.item.name }}</td>
<td>{{ props.item.address }}</td>
</tr>
<tr v-else>
<td>{{ props.item.name }}</td>
<td>{{ props.item.address }}</td>
</tr>
</template>

Another approach that can be used is using computed properties to insert the index to each element in the data. This can be useful if you need to update the table later on as computed properties are updated automatically.
For example, say the item data is stored in items.
data() {
return {
items: [{
fruit_name: 'Banana',
calories: 30
}, {
fruit_name: 'Apples',
calories: 40
}]
}
}
Here, every element to be itself plus additional attribute, i.e. index. Element addition is achieved using spread operator. All mapped elements are combined into single array using functional-programming style of map function.
computed: {
itemsWithIndex: () {
return this.items.map(
(items, index) => ({
...items,
index: index + 1
}))
}
}
Note: index: index+1 will make the numbering start from 1.
Then, inside headers data needed for v-data-table, you can make reference to index item data for numbering.
data() {
return {
items: {
...
},
headers: [{
text: 'Num',
value: 'index',
},
{
text: 'Fruit Name',
value: 'fruit_name',
},
{
text: 'Calories',
value: 'calories',
}
]
}
}
Codepen example: https://codepen.io/72ridwan/pen/NWPMxXp
Reference

<template slot="items" slot-scope="props">
<tr v-bind:class="getClass(props.item.name)">
<td>{{ props.item.name }}</td>
<td>{{ props.item.address }}</td>
</tr>
</template>
<script>
export default {
methods: {
getClass: function (name) {
if (name == 'XYZ') return 'header2';
},
}
}
</script>
<style>
.header2 {
// added style here
}
<style>

Related

Vue: [Vue warn]: Error in render: "TypeError: product.data is not a function"

I am trying to retrieve the data from cloud firestore database.
But I got an error,
[Vue warn]: Error in render: "TypeError: product.data is not a
function"
I want to show the each product name and price in my table.
But I have no idea why this issue comes up.
So I hope somebody can help me out.
If I don't use data() in the vue template, I can see all the data as I expected.
<template>
<h3>Product List</h3>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Modify</th>
</tr>
</thead>
<tbody>
<tr v-for="(product, index) in products" :key="index">
<td>{{ product.data().name }}</td>
<td>{{ product.data().price }}</td>
<td>
<button #click="editProduct(product)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { fb, db } from '../firebase'
export default {
name: 'Products',
props: {
msg: String
},
data () {
return {
products: [],
product: {//object
name: null,
price: null
}
}
},
methods: {
editProduct(product) {
$('#edit').modal('show')
},
readData() {
db.collection("products").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.products.push(doc.data());
});
});
},
saveData() {
// Add a new document with a generated id.
db.collection("products").add(this.product)
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
this.product.name = "",
this.product.price = ""
this.readData()
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
}
},
created() {
this.readData();
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
I will have to agree with #Mostafa, the naming convention is not very readable. Your error is telling you that you are trying to invoke a function that is not a function or does not exist in your data.
Change:
<td>{{ product.data().name }}</td>
<td>{{ product.data().price }}</td>
To:
<td>{{ product.name }}</td>
<td>{{ product.price }}</td>
This should fix it, as you are iterating over the products list (of which isn't clear), so i advise you should change:
<tr v-for="(product, index) in products" :key="index">
<td>{{ product.name }}</td>
<td>{{ product.price }}</td>
<td>
<button #click="editProduct(product)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
To:
<tr v-for="(productItem, index) in products" :key="index">
<td>{{ productItem.name }}</td>
<td>{{ productItem.price }}</td>
<td>
<button #click="editProduct(productItem)" class="btn btn-primary">Edit</button>
<button #click="deleteProduct(productItem.id)" class="btn btn-danger">Delete</button>
Your code is very confusing.
I don't understand why you are calling data method on product and why you have product and products in your data when you just need one.
So i'm assuming Vue is mixing product in your for loop and the product object in your data.
So either change the product name in your for loop to something else:
v-for="(item,index) in products"
or change product in your data (just remove it if you can) cause it doesn't have any data method in it.

Select and change a single table cell color per row with angular 6

I am trying to make a table in which I will be able to select a cell and change its color. Only 1 cell per row can be selected. When selected, its color should be red. When another is clicked, its color should change back to what it was before. I have been trying this for days, but no success. Only made it to change color of a whole row or column, but not a single cell. Can it be done?
Here is my template code:
<table id="table2" class="table table-bordered text-center">
<thead class="thead-light">
<th>Criteria</th>
</thead>
<tbody>
<tr *ngFor="let criter of rows;">
<td>{{ criter.criteria1 }}</td>
<td>{{ criter.criteria2 }}</td>
<td>{{ criter.criteria3 }}</td>
<td>{{ criter.criteria4 }}</td>
</tr>
<tbody>
</table>
As for CSS, it just needs this class (I think):
.on { background-color: "red"; }
That is what got ATM. If you need some more info let me know. Any help would be appreciated.
changeBG(val) { // on tr element
// val is event.target
let table = document.querySelector('#table2');
let selectedCells = table.getElementsByClassName('on');
if (val.tagName !== 'TD') {
return;
}
if (selectedCells.length) {
selectedCells[0].className = '';
}
val.className = 'on';
}
I don't know much about the angular dom interaction, but hopefully you can find the way through this

Populating HTML table rows with objects containing an array using Vue

I'm trying to populate rows in an HTML table using the Vue framework - the data is as seen below:
TeamRows: [
{ team: 'One', times: ['1', '2', '3'] },
{ team: 'Two', times: ['4', '5', '6'] },
{ team: 'Three', times: ['7', '8', '9'] }
]
I've tried following this codepen, but with bad result - this is my HTML:
<tbody>
<tr v-for="(row, rindex) in teamRows">
<td>{{rindex}}</td>
<template>
<cell v-for="(value, vindex) in row" :value="value" :vindex="vindex" :rindex="rindex"></cell>
</template>
</tr>
</tbody>
</table>
<template id="template-cell">
<td>{{ value }}</td>
</template>
And this is the Vue component:
Vue.component('cell', {
template: '#template-cell',
name: 'row-value',
props: ['value', 'vindex', 'rindex']
});
I would like the team to go in the first column in a row and the times to follow along in as many columns as there are times. Hope someone with more Vue knowledge is able to help me out here. Cheers.
Turns out the reason is you're using in-DOM template and browser moves unknown cell element above the v-for, and Vue can't access row value anymore: https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats
A solution without cell component, just with inline cell elements, works fine. Also, template wrapper is not needed in a table template:
new Vue({
el: '#app',
data: {
teamRows: [
{ team: 'One', times: ['1', '2', '3'] },
{ team: 'Two', times: ['4', '5', '6'] },
{ team: 'Three', times: ['7', '8', '9'] }
]
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<table>
<tbody>
<tr v-for="row in teamRows" :key="row.team">
<td>{{ row.team }}</td>
<td v-for="time in row.times">{{ time }}</td>
</tr>
</tbody>
</table>
</div>
Also, as a result of a discussion, you can still use a component if you wrap your table into another component for example, so that browser don't interfere and Vue has a chance to render everything properly:
new Vue({
el: '#app',
data: {
teamRows: [
{ team: 'One', times: ['1', '2', '3'] },
{ team: 'Two', times: ['4', '5', '6'] },
{ team: 'Three', times: ['7', '8', '9'] }
]
},
components: {
'mytable': {
template: `<table>
<tbody>
<tr v-for="row in rows" :key="row.team">
<td>{{ row.team }}</td>
<cell v-for="time in row.times" :value="time" :key="time"></cell>
</tr>
</tbody>
</table>`,
props: ['rows'],
components: {
'cell': {
template: `<td>{{ value }}</td>`,
props: ['value'],
}
}
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<mytable :rows="teamRows"></mytable>
</div>

Binding two-way in Vuejs not working on display

I have a project in Laravel for backend and VueJs for Front end.
I fetch data with my vueJs object using Api programmed in Laravel. My data is Fetched. In my example i get Article data.
fetchFamily: function(level , id){
this.$http.get('/api/family/' + id, function (data) {
var select_zone = 'options' + level
this.$set(select_zone, data);
})
//Fetch Article
this.$http.get('/api/family/' + id +'/material', function (data) {
this.$set('materials', data);
})
},
onSelectArticle: function(id){
var self = this;
jQuery.each(this.materials,function(idx,dta){
if(dta.id == id){
dta.qte = 0
self.items.push(dta);
return false;
}
});
$('#myModalArticle').modal('hide');
}
But when i want to initialize the quantity data to 0.
dta.qte = 0
I have a problem that in my table i have a input binding to this data.
<tr v-for="item in items">
<td class="hidden-sm"> #{{ item.code }}</td>
<td width="20%"> #{{ item.textes[0].texte }}</td>
<td>18.00</td>
<td><input type="text" v-model="item.qte" ></td>
<td>#{{ item.code }}</td>
<td>Colis</td>
<td>10%</td>
<td>16.20</td>
<td>#{{ item.qte * item.prices[0].price }}</td>
<td>{{ 18 * 40 * 1.17 }}</td>
</tr>
And when i am trying to change this value, in my screen the value doesn't change. And in my console when i check the value the value was changed.!!
vmApp.items[0].qte
Thank you for your Help!

Return Data via Meteor Method within a Loop

I'm looping through a list of credit card transactions and need to call out to the credit card processor to get the current status. I tried to use a helper that calls a method, but it doesn't get rendered on the template. If I log to the console, I can see that the results are properly being returned, though.
<tbody>
{{#each donations}}
<tr>
<td>{{ transactionId }} {{ status transactionId }}</td>
<td>{{ donorName donor }}</td>
<td>{{ donorEmail donor }}</td>
<td>{{ formatMoney amount }}</td>
<td>{{ createdAt }}</td>
</tr>
{{/each}}
</tbody>
Pulling the data:
donations: function() {
return Donations.find({
type: 'Credit Card',
createdAt: { $gte: new Date('Jan 1, 2015'), $lt: new Date('Jun 30, 2015') }
});
},
The status helper:
status: function(transactionId) {
var transaction = Meteor.call('getTransactionInfo', transactionId, function(error, result) {
console.log(result);
return result.status;
});
}
And the method:
getTransactionInfo: function(transactionId) {
var transaction = Meteor.wrapAsync(gateway.transaction.find, gateway.transaction);
var response = transaction(transactionId);
return response;
},
I found several questions that talked about putting the data in a ReactiveVar or Session variable, but I don't know how I could use that, considering that I am returning the info for every instance of the loop.
You can create a new template donation. Each row in the table will be its own donation instance, like this:
<tbody>
{{#each donations}}
{{> donation }}
{{/each}}
</tbody>
Now inside the onCreated for the donation template, create a ReactiveVar. Then immediately call the method, and in the method's callback, set the ReactiveVar. Since each row is its own template instance, each row will end up with its own ReactiveVar.
Template.donation.onCreated(function () {
var status = new ReactiveVar(null);
this.status = status;
Meteor.call('getTransactionInfo', this.data.transactionId, function (err, result) {
if (err) { /* handle it */ }
status.set(result);
});
});
Template.donation.helpers({
status: function () { return Template.instance().status.get(); },
/* rest of the helpers */
});
Now when the template is first created, the method call is still ongoing, so status.get() returns null. We have to test for this and display a loading spinner. After the method call completes, status.get() will be set to the result, so the spinner will be replaced with the value.
<tr>
<td>
{{ transactionId }}
{{#if status}}
{{ status }}
{{else}}
loading... <!-- or display a spinner -->
{{/if}}
</td>
<td>{{ donorName donor }}</td>
<td>{{ donorEmail donor }}</td>
<td>{{ formatMoney amount }}</td>
<td>{{ createdAt }}</td>
</tr>
From a security pov you've just exposed a lookup to your bank's systems from your (untrusted) clients. Anyone can run Meteor.call('getTransactionInfo', this.data.transactionId...) from their browser and that will end up hitting your bank. Great DDOS vector. Even absent malicious users these computations will end up running repeatedly for every transaction.
Better approach: run a cron job on your server that periodically checks the status of transactions (until they have cleared and no longer need checking) and put those stati into your donation collection.

Resources