https://imgur.com/f6Tk99v
I can't see anything that is preventing my column headers from showing up. I was able to duplicate the same effect by pasting the example datatable to the expansion template (see below).
Has anyone ever seen this happen before?
Thanks.
Here's the row detail component:
Code: Select all
import React from 'react'
import { apiCall } from '../../common/api'
import { debugLog, errorTypes } from '../../common/global'
import {ProgressBar} from 'primereact/progressbar'
// import { showGrowl, growlTypes } from '../../common/Growls'
import {Growl} from 'primereact/growl'
import {DataTable} from 'primereact/datatable'
import { Column } from 'primereact/column';
export default class JobDetail extends React.Component{
constructor() {
super()
this.state = {
apiCallComplete: false,
project: {},
detailRows: [],
tasks: [],
}
this.fetchData = this.fetchData.bind(this)
}
fetchData() {
const {job, token} = this.props
// get project detail
apiCall('fetchTable', 'returnTable', `view_project_detail where "ProjectID" = ${job.ProjectID}`, token)
.then( payload => {
debugLog("Jobs.js", "Fetch project detail", payload)
let projectDetailDataTableRows = []
if (payload.data.rows[0].ProjectID === job.ProjectID) {
for (let [key, value] of Object.entries(payload.data.rows[0])) {
if (key === 'lastchecktime') {
}
switch(key){
case 'lastchecktime':
if (value) {
const date = new Date(value)
value = date.toString()
}
break
case 'Complete' :
(value) ? value = 'Yes' : value = 'No'
break
default :
break
}
projectDetailDataTableRows.push({projectAttribute: key, projectValue: value})
}
this.setState({project: payload.data.rows[0], detailRows: projectDetailDataTableRows})
}
})
.catch( error => {
// errors are handled in api.js
// if (error === errorTypes.ERROR_TOKEN_EXPIRED )
// showGrowl(growlTypes.GROWL_TOKEN_EXPIRED, this.growl)
})
// get task detail
apiCall('fetchTable', 'returnTable', `view_tasks where "ProjectID" = ${job.ProjectID}`, token)
.then( payload => {
debugLog('JobDetail.js', 'fetch task detail ', payload)
this.setState({ apiCallComplete: true , tasks: payload.data.rows })
})
.catch( error => {})
}
componentDidMount() {
this.fetchData()
}
render() {
const {job} = this.props
// const { project } = this.state
return(
<div >
{
this.state.apiCallComplete &&
<div className="p-grid p-fluid" style={{padding:'2em 1em 1em 1em'}}>
<div>
<div className="p-col-12" style={{}}>
<h1>{`${job.ClientName} - ${job.ProjectName}`}</h1>
</div>
<div className='p-col-12 '>
<div className="p-grid p-fluid">
<div className="p-md-4">
{/**stateKey={`projectDetail${project.id}`} stateStorage="local" */}
<DataTable value={this.state.detailRows} >
<Column field="projectAttribute" header="projectAttribute"/>
<Column field="projectValue" header="projectValue" />
</DataTable>
</div>
<div className="p-md-8">
<DataTable header="Task Detail" value={this.state.tasks} ref={el => this.dt = el} responsive={true}>
<Column field="Task" header={"Task"}/>
<Column field="Description" header="Description"/>
<Column field="employee" header="Employee"/>
<Column field="PctTimeRqd" header="% Time Required"/>
<Column field="Hours" header="Hours"/>
<Column field="StartDate" header="Start Date"/>
<Column field="Complete" header="Complete"/>
<Column
field={"ProjectName"}
columnKey="ProjectName"
header={"Job Name"}
sortable={true}
/>
</DataTable>
</div>
</div>
</div>
</div>
</div>
}
{
!this.state.apiCallComplete &&
<ProgressBar mode="indeterminate"/>
}
</div>
)
}
}
Here's my parent component:
Code: Select all
import React, {Component} from 'react';
import {DataTable} from 'primereact/datatable'
import {Column} from 'primereact/column'
import { apiCall } from '../../common/api'
import { withCookies } from 'react-cookie'
import { debugLog, handleError } from '../../common/global'
import { ProgressBar } from 'primereact/progressbar'
import {MultiSelect} from 'primereact/multiselect'
import {Button} from 'primereact/button'
import JobDetail from './JobDetail'
import { showGrowl, growlTypes } from '../../common/Growls'
import { errorTypes } from '../../common/global'
import {Growl} from 'primereact/growl'
// import util from 'util'
class Jobs extends Component {
constructor() {
super()
this.state = {
expandedRows : null,
offices: null, // selected offices from filter
clients: null, // selected clients from filter
jobs: null, // selected jobs from filter
officeChoices: [
{label: 'CO', value: 'CO'},
{label: 'JAX', value: 'JAX'},
{label: 'MEM', value: 'MEM'},
{label: 'ROS', value: 'ROS'},
{label: 'TOR', value: 'TOR'},
{label: 'RE', value: 'RE'},
],
jobChoices: [],
clientChoices: [],
}
this.fetchTable = this.fetchTable.bind(this)
this.onOfficeChange = this.onOfficeChange.bind(this)
this.onJobChange = this.onJobChange.bind(this)
this.onClientChange = this.onClientChange.bind(this)
this.export = this.export.bind(this)
}
rowExpansionTemplate = data => {
const { cookies } = this.props
return(
<JobDetail
token={cookies.get('token')}
job={data}
/>)
}
// format Project Start Date Column
dateTemplate = (rowData, column) => {
const date = new Date(rowData.ProjectStartDate)
return <span>{date.toDateString()}</span>
}
export() {
this.dt.exportCSV()
}
fetchTable() {
// get table from database and update component state
const {cookies} = this.props
apiCall("fetchTable", "returnTable", "view_projects", cookies.get('token'))
.then(payload => {
debugLog("Jobs.js","fetch jobs view ",payload)
const {data} = payload
// generate columns from query data
// if (data.fields) {
// let cols = data.fields.map( col => {
// return <Column
// key={col.columnID}
// field={col.name}
// header={col.name}
// sortable={true}
// />
// })
// this.setState({cols})
// generate rows from query data
if (data.rows) {
const jobList = data.rows.map( row => {
return {label: row.ProjectName, value: row.ProjectName}
})
this.setState({
rows: data.rows,
// apiCallComplete: true,
jobChoices: jobList,
})
}
// }
})
// query client mult-select list
.then(() => {
apiCall("fetchTable", "returnTable", "view_client_select", cookies.get('token'))
.then(payload => {
debugLog("Jobs.js", "api call client select view", payload)
const {data} = payload
const clientList = data.rows.map( row => {
return( {label: row.ClientName, value: row.ClientName })
})
this.setState({clientChoices: clientList, apiCallComplete: true})
})
.catch( error => console.error(error))
})
.catch(error => {
handleError(error, "Jobs.js")
if (error === errorTypes.ERROR_TOKEN_EXPIRED)
showGrowl(growlTypes.GROWL_TOKEN_EXPIRED, this.growl)
})
}
componentDidMount() {
// call fetchTable() when component mounts for initial table load
this.fetchTable()
// update filter state from cookies
const { cookies } = this.props
const officeSelection = cookies.get('jobs_officeSelection')
const jobSelection = cookies.get('jobs_jobSelection')
const clientSelection = cookies.get('jobs_clientSelection')
this.setState({
offices: officeSelection,
clients: clientSelection,
jobs: jobSelection,
})
}
onOfficeChange(event) {
// handle office filter selection
this.dt.filter(event.value, 'LocationCode', 'in')
this.setState({offices: event.value})
// save filter to cookies
const { cookies } = this.props
cookies.set('jobs_officeSelection', event.value, { path: '/'})
}
onClientChange(event) {
// handle filter selection
this.dt.filter(event.value, 'ClientName', 'in')
this.setState({clients: event.value})
// save filter to cookies
const { cookies } = this.props
cookies.set('jobs_clientSelection', event.value, { path: '/'})
}
onJobChange(event) {
// handle filter selection
this.dt.filter(event.value, 'ProjectName', 'in')
this.setState({jobs: event.value})
// save filter to cookies
const { cookies } = this.props
cookies.set('jobs_jobSelection', event.value, { path: '/'})
}
render() {
let officeFilter = <MultiSelect
style={{width: '100%'}}
value={this.state.offices}
options={this.state.officeChoices}
onChange={this.onOfficeChange}
/>
let clientFilter = <MultiSelect
style={{width: '100%'}}
value={this.state.clients}
options={this.state.clientChoices}
onChange={this.onClientChange}
filter={true}
/>
let jobFilter = <MultiSelect
style={{width: '100%'}}
value={this.state.jobs}
options={this.state.jobChoices}
onChange={this.onJobChange}
filter={true}
/>
let header = <div style={{textAlign:'left'}}><Button type="button" icon="pi pi-external-link" alt="Export current table state." iconPos="left" label="CSV" onClick={this.export}></Button></div>;
return (
<div className="p-grid">
<Growl life={3000} ref={el => this.growl = el} style={{marginTop: 50}}/>
<div className="p-col-12">
<div className="card">
<h1>Jobs</h1>
{
// show loading bar while data loads
!this.state.apiCallComplete &&
<ProgressBar mode="indeterminate"/>
}
{ this.state.apiCallComplete &&
<DataTable
ref={el => this.dt = el }
value={this.state.rows}
header={header}
expandedRows={this.state.expandedRows}
onRowToggle={ e => this.setState({ expandedRows: e.data })}
responsive={true}
reorderableColumns={true}
rowExpansionTemplate={this.rowExpansionTemplate}
dataKey="ProjectID"
globalFilter={this.state.globalFilter}
stateKey="tablestate-jobs1"
stateStorage="local" // session storage seems to be the only option that works properly
>
<Column key={'expander'} expander={true} style={{width: '3em'}}/>
<Column
field={"ProjectName"}
columnKey="ProjectName"
header={"Job Name"}
sortable={true}
filter={true}
filterElement={jobFilter}
/>
<Column
field={"ClientName"}
columnKey="ClientName"
header={"Client"}
sortable={true}
filter={true}
filterElement={clientFilter}
/>
<Column
field={"LocationCode"}
columnKey="LocationCode"
header={"Office"}
sortable={true}
filter={true}
filterElement={officeFilter}
/>
<Column
field={"JobNumber"}
columnKey="JobNumber"
header={"Job Number"}
sortable={true}
filter={true}
/>
<Column
field={"ProjectStartDate"}
columnKey="ProjectStartDate"
header={"Start Date"}
sortable={true}
body={this.dateTemplate}
filter={true}
/>
</DataTable>
}
</div>
</div>
</div>
);
}
}
export const JobsWithCookies = withCookies(Jobs)
I have tried pasting the example datatable component as the expanded row detail with the same results
https://imgur.com/qEb8CRc
Code: Select all
rowExpansionTemplate = data => {
return(
<DataTable value={this.state.cars}>
<Column field="vin" header="Vin" />
<Column field="year" header="Year" />
<Column field="brand" header="Brand" />
<Column field="color" header="Color" />
</DataTable>
)