DataTable column headers not displaying in nested table

UI Components for React
Post Reply
hwpeden
Posts: 3
Joined: 05 Aug 2019, 17:29

08 Aug 2019, 17:01

I have a datatable that has expandable rows with two datatable elements in them. For the life of me I can't get the column headers to show up in the nested tables.


Image 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
Image 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>
            )

hwpeden
Posts: 3
Joined: 05 Aug 2019, 17:29

14 Aug 2019, 18:11

It looks like the <th> that gets rendered by the <DataTable> is inheriting the css from the t-body of the parent table. They are hiding the column name from each of the body cells, thus hiding the column names in the nested datatable.

Code: Select all

	.p-datatable-responsive .p-datatable-tbody>tr>td .p-column-title {
		display: none;
	}

aragorn
Posts: 3706
Joined: 29 Jun 2013, 12:38

10 Sep 2019, 12:22

Hi,

This issue is fixed for the next version. But, the expanded table doesn't support responsive feature. Please create a github issue for this.

Best Regards

hwpeden
Posts: 3
Joined: 05 Aug 2019, 17:29

10 Sep 2019, 15:21

aragorn wrote:
10 Sep 2019, 12:22
Hi,

This issue is fixed for the next version. But, the expanded table doesn't support responsive feature. Please create a github issue for this.

Best Regards
Create an issue specifically for responsive nested table support?

aragorn
Posts: 3706
Joined: 29 Jun 2013, 12:38

11 Sep 2019, 08:27

https://github.com/primefaces/primereact/issues

You can use this link to create a github ticket.

Thanks a lot!

Post Reply

Return to “PrimeReact”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 1 guest