Vue JS unable to properly show data table (v-for) - firebase

i'm trying to show a table of data that is coming from Firebase Firestore, i've already managed to put all data into a array, but when i try to show that content, the entire array shows up instead of the single items, see the image:
And heres my code:
<template>
<v-simple-table>
<template v-slot:default>
<thead>
<tr>
<th class="text-left">
Name
</th>
<th class="text-left">
Calories
</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in result"
v-bind:key="index"
>
<td>{{ result }}</td>
</tr>
</tbody>
</template>
</v-simple-table>
</template>
<script>
import firebase from 'firebase'
import {db} from '../service/firebase'
export default {
data () {
return {
userName: null,
result: [],
name: null,
email: null,
userMail: null,
telefone: null,
userPhone: null,
userAccept: null,
}
},
async created() {
var userData = []
await db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
userData.push(doc.data())
});
});
this.result = userData.map(a => a.name)
console.log(result)
}
}
</script>
How do i show a table of single items of the array instead of a table of arrays?
Thank you in advance!

You're printing the whole content using {{result}}, the right syntax is the following :
<tr v-for="(item, index) in result" v-bind:key="index" >
<td v-for="(record,i) in item" :key="i">{{ record }}</td>
</tr>

Related

How to pre process the key inside loop and show it as label in Vue 3

I want to loop through the following json object:
 
{countryId: 1, countryName: 'Bangladesh4', countryShortName: 'BD4', authStatus: 'U', createdBy: 'nasir', …}
I want to show this json object as follows:
Country Id: 1
Country Name: Bangladesh
and so on. Actually I need to add a space at every capital letter of a camel case word and make the first letter capital. How can I do this in vue 3?
My try:
<table>
<tbody>
<tr v-for="(value, key) in data">
<th>{{ key }} </th>
<td>{{ value }}</td>
</tr>
</tbody>
</table>
I have not tested this code. But I would create a computed property, which creates an object with the correct labels based on the keys in the data:
const labels = computed(() => {
const newLabels = {}
data.forEach(item => {
Object.key(key => {
newLabels[key] = key.replace( /([A-Z])/g, " $1" );
})
})
return newLabels;
})
The object created should look like this: {countryId: 'country Id', countryName: 'country Name', ...}. It is flexible as it will run over all objects in the data array, collecting and converting all possible keys. Downside may be performance when you have a huge array. If all keys are the same for the objects in data, you also just might create a labels object manually.
Now you can use this in your template:
<th style="text-transform: capitalize;">{{ labels[key] }} </th>
I added the style to transform the first letter to a capital.
As said, I did not have an opportunity to test this, but I hope it helps you any further.
you can display name as below
<table>
<tbody>
<tr v-for="(value, key) in data">
<th v-if="key=='countryId'">Country Id</th>
<th v-if="key=='countryName'">Country Name</th>
...
<td>{{ value }}</td>
</tr>
</tbody>
</table>

set min width on <td> in a reactstrap Table

I have searched for a solution with no avail. I need to set a minimum width on my RESPONSIVE table columns in a Table imported from reactstrap.
This table is always going to have a DYNAMIC amount of columns. I have a select as my <th> and I want to set the to a minimum width so users can obviously read the select options.
Here is my component below
import React, { Fragment, useState, useContext, useMemo } from 'react';
import { CustomInput,Input, Table} from 'reactstrap';
const TableComponent = ({ register, errors, watch }) => {
const TableRow = ({ data }) => (
<tr className="align-middle">
{data.map((customer, index) => (
<td className="text-nowrap" key={index}>{customer}</td>
))}
</tr>
);
return (
<Fragment>
<Table responsive bordered striped hover>
<thead>
<tr>
{
fileContacts.map((contact, index) => (
<th className="bg-primary pr-1 pl-1 pt-2 pb-2" scope="col" key={index}>
<Input
type="select"
className="fs--1"
name="selectHeader"
id="selectHeader"
>
<option>First name</option>
<option>Last name</option>
<option>Email</option>
</Input>
</th>
))}
</tr>
</thead>
<tbody>
{
upload.contacts.slice(0, 10).map((customer, index) => (
<TableRow data={customer} key={index}/>
))
}
</tbody>
</Table>
</Fragment>
);
};
export default TableComponent;
Here are two images. These are what it looks like on mobile or smallest laptop size
Here is the solution. In the TableRow component that is being rendered in the body, you need to add a style prop to the <td>
Note: this must be an object within jsx brackets or else you will get an error.
Here is a copy of the TableRow
const TableRow = ({ data }) => (
<tr className="align-middle">
{data.map((customer, index) => (
<td style={{minWidth: 150}} key={index}>{customer}</td>
))}
</tr>
);
Here was my expected output

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.

How to fetch and display data in React js but Line 26: 'cusList' is not defined no-undef error is coming up,pls healp.tnx

How to fetch and display data in ASP.net core using React js Line 26: 'cusList' is not defined no-undef error is coming up.
import React, { Component } from 'react';
import './Map';
export class FetchCustomer extends Component {
static displayName = FetchCustomer.Name;
constructor(props) {
super(props);
this.state = { customers: [], loading: true };
}
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderCustomerTable(this.state.cusList);
return <table className='table'>
<thead>
<tr>
<th></th>
<th>Id</th>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{cusList.map(cus =>
<tr key={cus.Id}>
<td></td>
<td>{cus.Id}</td>
<td>{cus.Name}</td>
<td>{cus.Address}</td>
<td>
<a className="action" onClick={(id) => this.handleEdit(cus.Id)}>Edit</a> |
<a className="action" onClick={(id) => this.handleDelete(cus.Id)}>Delete</a>
</td>
</tr>
)}
</tbody>
</table>;
fetch('api/Customer/Index')
.then(response => response.json())
.then(data => { this.setState({ cusList: data, loading: false }) });
}
}
Following changes are needed in your code...
In your constructor change the last line of code with following:
this.state = { customers: [], loading: true, cusList: [] };
And in the "tbody" section please change the code to:
<tbody>
{this.state.cusList.map(cus =>
<tr key={cus.Id}>
<td></td>
<td>{cus.Id}</td>
<td>{cus.Name}</td>
<td>{cus.Address}</td>
<td>
<a className="action" onClick={(id) => this.handleEdit(cus.Id)}>Edit</a> |
<a className="action" onClick={(id) => this.handleDelete(cus.Id)}>Delete</a>
</td>
</tr>
)}
</tbody>
This should work.
Also it's pretty clear from the error itself about what you are missing.
Hope it helps.

Vuejs pulling database from Sqlite3 over axios; DOM not re-rendering

So I am working on a project including Flask, VueJS, Sqlite3 and Axios. On the VueJS side, using a 'GET' request I am getting all the database data and saving it in a JavaScript array. I am trying to iterate through the array and show all the database information in HTML. If I 'refresh' the page the information is displayed. But I would like the information to update 'live' when I add information to the database from a 'POST' axios request to FLASK.
I just put the critical code down below; I tried to make it shorter.
So the axios 'GET' request fetches the entire sqlite3 database; then saves it in the 'database[]' array
The database has three columns; id, FIRST_NAME, LAST_NAME
#app.route('/api/database', methods = ['POST'])
def database_write():
if request.method == 'POST':
conn = sql.connect('test.sqlite3')
conn.execute("INSERT INTO DATABASE (FIRST_NAME,LAST_NAME) \
VALUES (?, ?)", (request.json[0], request.json[1]))
conn.commit()
print("Records created successfully")
conn.close()
return("OK")
#app.route('/api/getdatabase', methods = ['GET'])
def database_get():
if request.method == 'GET':
conn = sql.connect('test.sqlite3')
cursor = conn.cursor()
cursor.execute("SELECT * FROM DATABASE ORDER By id")
rows = cursor.fetchall()
return jsonify(rows)
<template>
<div class="form-group col-6">
<input class="form-control" v-model="form1" type="text">
<input class="form-control" v-model="form2" type="text">
<button class="btn btn-primary" type="submit" #click='writeToDatabase'>Submit</button>
</div>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">First Name</th>
<th scope="col">Last Name</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="database in database" :key="database[0]">
<td>{{ database[1] }}</td>
<td>{{ database[2] }}</td>
<td>
<div class="btn-group" role="group">
<button type="button" class="btn btn-danger btn-sm" #click="deleteDatabaseValue(database)">Delete</button>
</div>
</td>
</tr>
</tbody>
</table>
</template>
<script>
data () {
return {
form1: "",
form2: "",
database: [],
}
},
writeToDatabase () {
const path = `http://localhost:5000/api/database`
axios.post(path, [this.form1, this.form2])
this.form1 = ""
this.form2 = ""
},
getDatabase() {
const path = 'http://localhost:5000/api/getdatabase'
axios.get(path)
.then((response) => {
// console.log(res.data)
this.database = response.data;
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
},
created() {
this.getDatabase();
},
</script>
I want the v-for to render anytime I add a value to the database or delete a value from the database. It only rerenders when I refresh the page manually and the 'created()' function is called which resets the database.

Resources