I'm trying to create a dynamic table that renders data inserted based on a format of
{headers: ["header1", "header2"], rows: [["data1", "data2"], ["moredata", "wowoso muchdata"]]}
Rows is just an array of arrays and each array is a row in the table.
I pass this data into a React component which renders the table. The code is the following:
export default class StandardTable extends React.Component<Props, State>{
constructor(props){
super(props);
this.state = {
tableData: this.props.data
}
}
render(){
return(
<div>
<table id="StandardTable">
<tbody>
{this.state.tableData.headers.map(function(header){
<th>{header}</th>
})}
</tbody>
<tbody>
{this.state.tableData.rows.map(function(row){
<tr>
{row.map(function(rowItem){
<td>{rowItem}</td>
})}
</tr>
})}
</tbody>
</table>
<style jsx>
{`
#StandardTable{
border: 1px solid black;
}`}
</style>
</div>
);
}
}
I am able to console log the data object and all the data is there. It's also iterating through the data in the map functions as I can check in console, but unfortunately the table shows up blank in practice.
can you try this, no need to return, you can use arrow function
<table id="StandardTable">
<tbody>
{this.state.tableData.headers.map((header) => (
<th>{header}</th>
))}
</tbody>
<tbody>
{this.state.tableData.rows.map((row)=>(
<tr>
{row.map((rowItem)=>(
<td>{rowItem}</td>
))}
</tr>
))}
</tbody>
</table>
Hope it will work.
It's because you forgot the return. Just do this in your map functions:
{this.state.tableData.headers.map(function(header){
return <th>{header}</th>
})}
There is no return in map
this.state.tableData.rows.map(function(row){
return( <tr>
{row.map(function(rowItem){
return <td>{rowItem}</td>
})}
</tr>)
})
Related
I was working on this json data with react-table, it displays yet horizontally in a single <td></td>, your inputs are highly appreciated.
export const COLUMNS = [
{
Header: 'mId',
accessor: (row) => {return row.skus.map(sku => sku.mId); }
}]
Please note that I can access the data and print but it looks weird.
Expected Output:
<td>sku2620222 </td>
<td>sku2620220</td>
<td>sku2680407 </td>
<td>sku2680408 </td>
<td>sku10980349 </td>
<td>sku2680406</td>
Real output:
<td> sku2620222sku2620220sku2680407sku2680408sku2680405sku10980349sku2680406</td>
Basically I want it to display in every row. Thanks a lot
Each item you map through needs to be in its own row. Then you can add as many table downs as you need. That way each time you map through it, it will render a new table row. Here is an extremely simple table you can follow.
export default function App() {
let data = [
{sku: "sku2620222"},
{sku: "sku2620220"},
{sku: "sku2680407"},
{sku: "sku2620222"},
{sku: "sku2680408"},
]
let tabledata = data.map(i => {
return (
<tr>
<td>
{i.sku}
</td>
</tr>
)
})
return (
<>
<table>
<thead>
<tr>
<th>
SKU
</th>
</tr>
</thead>
<tbody>
{tabledata}
</tbody>
</table>
</>
)
}
I use Firebase hosting in combination with ReactJS. if I include a parameter in the url on my localhost, this works fine. The configuration is as follows:
Only when I deploy it to the firebase hosting I get a white blank page. such as eg:
in my routes.js:
{
path: "/ontbijt-betaling/:id",
layout: ModalLayout,
exact: false,
component: PayBreakfastView
},
In my view:
import React from "react";
import { Container, Row, Col } from "shards-react";
import PayBreakfastComponent from "../../components/Frontend/PayBreakfastComponent";
import FooterView from "../Footer";
import HeaderView from "../Header";
const PayBreakfastView = (props) => (
<Container fluid >
<HeaderView />
<PayBreakfastComponent id={props.match.params.id}/>
<FooterView />
</Container>
);
export default PayBreakfastView;
and the component:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import { Row, Col, Card, CardHeader, CardBody, Button } from "shards-react";
import Firebase from 'firebase';
class PayBreakfastComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name:'',
mail:'',
shortDesc:'',
payment:[]
};
}
componentWillMount(){
console.log('mount')
let tempPayment = Firebase.database().ref('/clients/-uhfwoebfwioudb/content/temp-payments/'+this.props.id);
tempPayment.on('value', snapshot => {
let state = snapshot.val();
this.setState({
payment: state,
get: true
})
localStorage.setItem('name',state.name);
localStorage.setItem('mail',state.email);
localStorage.setItem('date',state.date);
localStorage.setItem('phone',state.phone);
localStorage.setItem('adres',state.adres);
localStorage.setItem('postal',state.zip);
localStorage.setItem('city',state.city);
localStorage.setItem('bookingID', state.bookingsnumber)
localStorage.setItem('amount',state.amount);
localStorage.setItem('shippingCost',state.shippingCost);
localStorage.setItem('unitPrice',state.unitPrice);
localStorage.setItem('total',state.totalPrice);
console.log(state.email)
})
}
payOrder(){
/* var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://app.biejanssen.nl/paymentBreak');
xhr.setRequestHeader("Content-Type", "application/json");
let data ={
totalPrice: this.state.payment.totalPrice,
nameClient: this.state.payment.name,
emailClient: this.state.payment.email,
}
xhr.send(JSON.stringify(data));
xhr.onload = () => {
console.log("status is:"+xhr.responseURL);
window.location.href=xhr.responseURL;
};*/
}
render() {
return (
<div className="home-page">
<Row className="contact-row">
<Col sm={12} className="contact-colum">
<h2>Ontbijt betalen</h2>
</Col>
</Row>
<Row>
<Col sm={3}></Col>
<Col sm={6} className="frontend-table">
<h2>Uw bestel overzicht</h2>
<form method="post" action={"https://app.biejanssen.nl/paymentBreak"} id="hook-form" >
<table>
<tr>
<td><span className="total-fat">Order nummer</span></td>
<td>{this.state.payment.bookingsnumber} <input type="text" value={this.state.payment.bookingsnumber} hidden/></td>
</tr>
<tr>
<td><span className="total-fat">Omschrijving</span></td>
<td>Ontbijt</td>
</tr>
<tr>
<td><span className="total-fat">Uw naam</span></td>
<td>{this.state.payment.name} <input type="text" name="nameClient" value={this.state.payment.name} hidden/></td>
</tr>
<tr>
<td><span className="total-fat">Uw e-mail</span></td>
<td>{this.state.payment.email} <input type="text" name="emailClient" value={this.state.payment.email} hidden/></td>
</tr>
<tr>
<td><span className="total-fat">Uw telefoonnummer</span></td>
<td>{this.state.payment.phone}</td>
</tr>
<tr>
<td><span className="total-fat">Aflever datum</span></td>
<td>{this.state.payment.date}</td>
</tr>
<tr>
<td><span className="total-fat">Aflever adres</span></td>
<td>{this.state.payment.adres}, {this.state.payment.zip}, {this.state.payment.city}</td>
</tr>
<tr>
<td><span className="total-fat">Aantal ontbijtjes</span></td>
<td>{this.state.payment.amount}</td>
</tr>
<tr>
<td><span className="total-fat">Prijs per ontbijt</span></td>
<td>€ {this.state.payment.unitPrice}</td>
</tr>
<tr>
<td><span className="total-fat">Bezorgkosten ontbijt</span></td>
<td>€ {this.state.payment.shippingCost}</td>
</tr>
<tr>
<td><span className="total-oder">Totaal</span></td>
<td><span className="total-oder">€ {this.state.payment.totalPrice} <input type="text" name="totalPrice" value={this.state.payment.totalPrice} hidden/></span></td>
</tr>
</table>
<button type="submit" form="hook-form">Betaal</button>
</form>
<Button onClick={()=>this.payOrder()} >Betaal bestelling!</Button>
</Col>
<Col sm={3}></Col>
</Row>
</div>
);
}
};
export default PayBreakfastComponent;
Example url is: https://app.biejanssen.nl/ontbijt-betaling/-MWTRAO7Lhjqc47-y6z-
Does anyone understand where the difference is or how this is possible?
If you look at browser DevTools you'll see the following error:
Uncaught SyntaxError: Unexpected token '<'
[
This error typically means a JavaScript was requested from the server and it returned HTML instead.
If you look at the source of https://app.biejanssen.nl/ontbijt-betaling/-MWTRAO7Lhjqc47-y6z- You'll find the script tag loading the main chunk from a relative path:
<script src="./static/js/main.cc963dc1.chunk.js"></script>
Resulting in loading the JavaScript file from:
https://app.biejanssen.nl/ontbijt-betaling/static/js/main.cc963dc1.chunk.js
The file file doesn't exist at that path and if you look at the resources loaded for https://app.biejanssen.nl/dashboard you'll find the JavaScript file actually exists at:
https://app.biejanssen.nl/static/js/main.cc963dc1.chunk.js
You need to update the the app to always load JavaScript and other resources from the root of the domain. Something like the following without the . at the start of the path:
<script src="/static/js/main.cc963dc1.chunk.js"></script>
Can anyone spot the issue here?
import React from 'react'
export default function CoinTable(props){
props.data.map(row=> {
console.log(row.first_name)
})
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th>Subscription</th>
</tr>
</thead>
<tbody>
{
props.data.map(row => {
<tr>
<td>{row.first_name} {row.last_name}</td>
<td>{row.phone}</td>
<td>{row.email}</td>
</tr>
})
}
</tbody>
</table>
)
}
For some reason the code appears on console but not on the screen. I am also printing from a JSON file if that helps.
You don't return the DOM in map.
props.data.map(row => {
return (
<tr>
<td>{row.first_name} {row.last_name}</td>
<td>{row.phone}</td>
<td>{row.email}</td>
</tr>
)
})
Or precisely:
props.data.map(row => (
<tr>
<td>{row.first_name} {row.last_name}</td>
<td>{row.phone}</td>
<td>{row.email}</td>
</tr>
))
I need to populate a dynamic amount of Tabs on an Angular 2 site using a For Loop that is using a subscribe to get data from a database service and I am wondering if it is even possible.
My data set is broken down by Classes: A, B and C and they each have a Sub-Class of 1 and 2. So I would like to have my results dynamically create 3 tabs (Tab A, Tab B, and Tab C). So far I have this working.
I then need each of these tabs to then display the data of their Sub-Classes. As of now the loop runs the 3 times and provides the data needed but every page just shows data for Class C as it was the last one to run and the model is updated with all of its data.
Below is what I have thus far.
classdata.component.html
<mat-tab-group>
<mat-tab *ngFor="let classresult of classresults;" label="Class -{{classresult.Class_Name}}">
<table class ="responstable">
<thead>
<tr>
<th>Sub-Class Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let subclassresult of subclassresults;">
<td>{{subclassresult.Sub_Class_Name}} </td>
<td>{{subclassresult.Value}} </td>
</tr>
</tbody>
</table>
</mat-tab>
</mat-tab-group>
classdata.component.ts
// Populate Class Level Data
this.databaseService.getClass()
.subscribe(classresults => this.classresults = classresults,
error => console.log('ERROR!'),
// Populate Sub-Class Level Data
() => { for (const classresult of this.classresults) {
this.selectedClassId = classresult.Class_ID;
console.log(this.selectedClassId);
this.databaseService.getSubClass(this.selectedClassId)
.subscribe(subclassresults => this.subclassresults = subclassresults);
}
}
);
database.service.ts
getClass(): Observable<ClassResult[]> {
const url = 'http://localhost:3000/c';
const data = ({
});
return this._http.post(url, data)
.pipe(
map((res) => {
console.log(res);
return <ClassResult[]> res;
})
);
}
getSubClass(Class_ID): Observable<SubClassResult[]> {
const url = 'http://localhost:3000/sc';
const data = ({
classid: Class_ID
});
return this._http.post(url, data)
.pipe(
map((res) => {
console.log(res);
return <SubClassResult[]> res;
})
);
}
You are fetching each Subclass for every parentClass but you are reassigning each result to the class variable this.subclassresults. Basically you are overwriting each previous result with the current result. Thats why every page just shows data for Class C.
There are many different solutions how you can solve this problem.
On solution could be you are using forkJoin Observable and save the result of your parentClass with their subClasses in their own object:
this.databaseService.getClass().pipe(
switchMap(classResults => {
const subClassRequests = classResults.map(
classResult => this.dabaseService
.getSubClass(classResult)
.pipe(map(subClassResults => {classResult, subClassResults}))
)
return forkJoin(subClassRequests)
})
).subscribe(results => this.results = results);
results holds your data as an array.
And in your template use it like this:
<mat-tab-group>
<mat-tab *ngFor="let result of results;" label="Class -{{result.classresult.Class_Name}}">
<table class ="responstable">
<thead>
<tr>
<th>Sub-Class Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let subclassresult of result.subclassresults;">
<td>{{subclassresult.Sub_Class_Name}} </td>
<td>{{subclassresult.Value}} </td>
</tr>
</tbody>
</table>
</mat-tab>
</mat-tab-group>
I implemented a small working Demo: StackBlitz Demo
The following code works:
#if ( Model.document.usesNumericRevision )
{
<tr>
<th>Major Revision</th>
<td>#Html.TextBoxFor( m => m.document.documentStatus.documentRevision.MajorRevision )</td>
</tr>
<tr>
<th>Minor Revision</th>
<td>#Html.TextBoxFor( m => m.document.documentStatus.documentRevision.MinorRevision )</td>
</tr>
}
else
{
<tr>
<th>Alphanumeric Revision</th>
<td>#Html.TextBoxFor( m => m.document.documentStatus.documentRevision.Revision )</td>
</tr>
}
Depending on the value of usesNumericRevision the appropriate HTML will display. But if the user checks / unchecks the checkbox, the view will not update. Is there a way to update the view without going back to the server?
The condition statement in the view is executed on the server and sent to the client. You need to use JavaScript to do it client side without going back to the sever.
Yes... but you need some jQuery to do the client side stuff.
<div id="NumericRevision">
<tr>
<th>Major Revision</th>
<td>#Html.TextBoxFor(m => m.document.documentStatus.documentRevision.MajorRevision)</td>
</tr>
<tr>
<th>Minor Revision</th>
<td>#Html.TextBoxFor(m => m.document.documentStatus.documentRevision.MinorRevision)</td>
</tr>
</div>
<div id="AlphanumRevision">
<tr>
<th>Alphanumeric Revision</th>
<td>#Html.TextBoxFor( m => m.document.documentStatus.documentRevision.Revision )</td>
</tr>
</div>
...
<script>
$(document).ready(function() {
//Initial state of the form
$("#AlphanumRevision").css("display","none");
// Add onclick handler to checkbox w/id "checkme"
$("#checkme").click(function(){
// If checked
if ($("#checkme").is(":checked")){
$("#AlphanumRevision").show("fast");
$("#NumericRevision").hide("fast");
}
else {
$("#AlphanumRevision").hide("fast");
$("#NumericRevision").show("fast");
}
});
});
</script>