react-bootstrap-table / react-bootstrap-table2

Next Generation of react-bootstrap-table
https://react-bootstrap-table.github.io/react-bootstrap-table2/
MIT License
1.27k stars 431 forks source link

The formatter property don't work, only work if the columns are defined inside of the component. #1264

Closed CACDX closed 4 years ago

CACDX commented 4 years ago

I have the columns defined in a other file, i want to import the columns and use it. All the columns work, but the column that have a button is show nothing. Only work if i put the columns inside of component that render the table. It's possible to make it from the outside and importing the columns?

Here is my code:

File columns.js import { Type } from 'react-bootstrap-table2-editor';

export const COLUMNS_MUTUAL = [{ id: 0, dataField: 'codmutual', text: 'Codigo', hidden: false, checked: true },...//here go a lot of columns { id: 23, dataField: 'visible', text: 'visibility', hidden: true, checked: true, }];

File MutualTable.js

import React, { useContext } from 'react' import BootstrapTable from 'react-bootstrap-table-next'; import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit'; import Container from 'react-bootstrap/Container' import paginationFactory from 'react-bootstrap-table2-paginator'; import cellEditFactory, { Type } from 'react-bootstrap-table2-editor'; import Row from 'react-bootstrap/Row' import Col from 'react-bootstrap/Col' import { MutualContext } from '../../context/mutualContext'; import Spinner from 'react-bootstrap/Spinner' import ButtonToolbar from 'react-bootstrap/ButtonToolbar' import Button from 'react-bootstrap/Button' import Card from 'react-bootstrap/Card'; import { COLUMNS_BIOQUIMICOS } from '../const/listBioqConst';

const MutualTable = ({ onAfterSaveCell }) => {

const { Mutuales, columns, COLUMNS_MUTUAL } = useContext(MutualContext)

const { SearchBar } = Search;

const Load = () => {
    return (<ButtonToolbar>
        <Button variant="primary" disabled>
            <Spinner
                as="span"
                animation="grow"
                size="sm"
                role="status"
                aria-hidden="true"
            />
            Loading...
    </Button>
    </ButtonToolbar>)
}

const addbuttonMenu = (columns) => {
    return [
        ...columns,
        {
            id: 24,
            dataField: 'action',
            isDummyField: true,
            text: 'Accion',
            formatter: (cellContent, row) => {
                console.log(cellContent, row)
                return (
                    <React.Fragment>
                        <Button type="button" onClick={(() => {
                            console.log(row.codmutual)
                        })} className='btn btn-danger btn-sm' >Borrar</Button>
                    </React.Fragment>)
            },
            hidden: false,
            checked: true,
            editable: false
        }

    ]
}

return (
    <React.Fragment>
        <ToolkitProvider
            keyField="id"
            data={Mutuales}
            columns={addbuttonMenu(columns)}
            search
        >
            {
                props => (

                    <React.Fragment>
                        <Card className='main'>
                            <Card.Header>
                                Realize la busqueda por cualquier campo:
                            </Card.Header>
                            <Card.Body>
                                <SearchBar {...props.searchProps} />
                            </Card.Body>
                        </Card>
                        <Container fluid="sm" className="main">
                            <Row>
                                <Col>
                                    <Card.Title className="main text-center" >MUTUALES</Card.Title>
                                </Col>
                            </Row>
                            <Row>
                                <Col>
                                    <BootstrapTable
                                        keyField="codmutual"
                                        noDataIndication={<Load />}
                                        data={Mutuales}
                                        // columns={ (columns || localStorage.getItem('configListMutual')) ? JSON.parse(localStorage.getItem('configListMutual')) : (COLUMNS_BIOQUIMICOS || columns)}
                                        columns={addbuttonMenu(columns)}

                                        pagination={paginationFactory()}
                                        cellEdit={cellEditFactory({
                                            mode: 'click',
                                            blurToSave: true,
                                            afterSaveCell: onAfterSaveCell
                                        })}
                                        striped
                                        hover
                                        condensed

                                    />
                                </Col>
                            </Row>
                        </Container>

                    </React.Fragment>
                )
            }
        </ToolkitProvider>
    </React.Fragment>
)

}

export default MutualTable;

File Mutual.js

import React, { useContext } from 'react'; import MutualTable from './MutualTable' import { updateModel } from '../../operation/updateModel' import url from '../../config' import { useAlert } from "react-alert"; import { MutualContext } from '../../context/mutualContext'; import Accordion from 'react-bootstrap/Accordion' import Card from 'react-bootstrap/Card' import Button from 'react-bootstrap/Button' import Container from 'react-bootstrap/Container' import Form from 'react-bootstrap/Form'

const Mutual = () => {

const { dispatch, COLUMNS_MUTUAL, columns } = useContext(MutualContext);

const alert = useAlert()

const handleAfterSaveCell = async (oldValue, newValue, row, column) => {
    console.log('After Saving Cell!!');
    console.log("oldValue " + oldValue)
    console.log("newValue " + newValue)
    console.log("row " + row.codmutual)
    console.log("column " + column.dataField)
    const data = {
        col: column.dataField,
        value: newValue
    }
    const res = await updateModel(`${url}/mutuales/update/${row.codmutual}`, data);
    if (res.success)
        alert.success("Cambios guardados").show;
    else alert.error(res.errors[0]).show
}

const handleChangeChk = (type) => {

    if (localStorage.getItem('configListMutual')) {
        let configListBioquimico = JSON.parse(localStorage.getItem('configListMutual'))

        let checkFind = configListBioquimico.find(m => (m.dataField == type.dataField));

        return checkFind.checked
    }
    else
        return type.checked
}

return (
    <React.Fragment>
        <Accordion className='main'>

            <Card>
                <Card.Header>
                    <Accordion.Toggle as={Button} variant="link" eventKey="0">
                        Ver columnas
                    </Accordion.Toggle>
                </Card.Header>
            </Card>
            <Accordion.Collapse eventKey="0">
                <Container fluid="sm">
                    <Form.Group controlId="formBasicCheckbox" className='main'>
                        {COLUMNS_MUTUAL.map(type => (
                            (type.dataField != 'codmutual' && type.dataField != 'visible') ?
                                <Form.Check inline key={`inline-${type.id}`} name={type.dataField} label={type.text} type="switch" id={`inline-${type.id}`}
                                    onChange={() => {
                                        dispatch({
                                            type: 'COLUMN_SELECT',
                                            arrColumns: columns,
                                            selectCol: event.target,
                                            config: 'configListMutual'
                                        })
                                    }}
                                    defaultChecked={handleChangeChk(type)}
                                />
                                : null))}
                    </Form.Group>
                </Container>
            </Accordion.Collapse>
        </Accordion>
        <MutualTable onAfterSaveCell={handleAfterSaveCell} />
    </React.Fragment>

);

}

export default Mutual;

AllenFang commented 4 years ago

@CACDX

  1. I don't know what's mean for "don't work" here
  2. Please follow the instruction to open an issue and create a simple and minimal example on codesandbox. That will be easy for contributors to identify and reproduce your issue.
CACDX commented 4 years ago

Edit dawn-forest-sdyrm

In codesandbox look great, but in my project not. In my case the buttons don't appears, i don't know why. In the bootstrapTable column props, if i put a variable that reference to a constant imported it's work fine, the button in the column appear, but if i put a variable that reference to a variable in useReducer, don't appear the button in the column.

I use a variable defined in useReducer that it's used to load the columns in bootstrapTable, the variable provided by a context.

Here is my context: import React, { createContext, useEffect, useReducer } from 'react' import { MutualList } from '../hooks/useBonomutual' import url from '../config' import { COLUMNS_MUTUAL } from '../components/const/columnsMutual' import { dataTableReducer } from '../reducers/dataTableReducer';

export const MutualContext = createContext()

const MutualContextProvider = props => {

console.log("Mutual context provider")

const { Mutuales } = MutualList(`${url}/mutuales`)

const [columns, dispatch] = useReducer(dataTableReducer,
    (localStorage.getItem('configListMutual')) ? JSON.parse(localStorage.getItem('configListMutual')) :
        (localStorage.setItem('configListMutual', JSON.stringify(COLUMNS_MUTUAL)), JSON.parse(localStorage.getItem('configListMutual'))));

return (
    <MutualContext.Provider value={{ COLUMNS_MUTUAL, columns, Mutuales, dispatch }}>
        {props.children}
    </MutualContext.Provider>
)

}

export default MutualContextProvider;

Here is the component that render the table: import React, { useContext, useState } from 'react' import { useHistory } from 'react-router-dom';

//Components import Loading from '../../components/Loading'

//Functions import { handleButtonRemove } from '../../operation/handleButton';

//Bootstrap Components and Datatables Components import BootstrapTable from 'react-bootstrap-table-next'; import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit'; import Container from 'react-bootstrap/Container' import paginationFactory from 'react-bootstrap-table2-paginator'; import cellEditFactory from 'react-bootstrap-table2-editor'; import Row from 'react-bootstrap/Row' import Col from 'react-bootstrap/Col' import Button from 'react-bootstrap/Button' import Card from 'react-bootstrap/Card';

//Context and Constants import { MutualContext } from '../../context/mutualContext'; import url from '../../config'

const MutualTable = ({ onAfterSaveCell }) => {

const { columns, Mutuales } = useContext(MutualContext)
const [hiddenRow, setHiddenRow] = useState([])
const history = useHistory();
const { SearchBar } = Search;

const addbuttonMenu = (columns, history) => {
    return [
        ...columns,
        {
            id: 24,
            dataField: 'action',
            isDummyField: true,
            text: 'Accion',
            formatter: (cellContent, row) => {
                console.log(cellContent, row)
                return (
                    <React.Fragment>
                        <Button type="button" onClick={(() => {
                            console.log(row.codmutual);
                            setHiddenRow(hiddenRow.concat(row.codmutual))
                            handleButtonRemove(`${url}/mutuales/remove/${row.codmutual}`, row.codmutual, history)

                        })} className='btn btn-danger btn-sm' >Borrar</Button>
                    </React.Fragment >)
            },
            hidden: false,
            checked: true,
            editable: false
        }

    ]
}

return (
    <React.Fragment>
        <ToolkitProvider
            keyField="id"
            data={Mutuales}
            columns={addbuttonMenu(columns)}
            search
        >
            {
                props => (

                    <React.Fragment>
                        <Card className='main'>
                            <Card.Header>
                                Realize la busqueda por cualquier campo:
                            </Card.Header>
                            <Card.Body>
                                <SearchBar {...props.searchProps} />
                            </Card.Body>
                        </Card>
                        <Container fluid="sm" className="main">
                            <Row>
                                <Col>
                                    <Card.Title className="main text-center" >MUTUALES</Card.Title>
                                </Col>
                            </Row>
                            <Row>
                                <Col>
                                    <BootstrapTable
                                        {...props.baseProps}
                                        keyField="codmutual"
                                        noDataIndication={<Loading />}
                                        hiddenRows={hiddenRow}
                                        data={Mutuales}
                                        columns={addbuttonMenu(columns, history)}
                                        pagination={paginationFactory()}
                                        cellEdit={cellEditFactory({
                                            mode: 'click',
                                            blurToSave: true,
                                            afterSaveCell: onAfterSaveCell
                                        })}
                                        striped
                                        hover
                                        condensed

                                    />
                                </Col>
                            </Row>
                        </Container>

                    </React.Fragment>
                )
            }
        </ToolkitProvider>
    </React.Fragment>
)

}

export default MutualTable;

Sorry for my english.

AllenFang commented 4 years ago

@CACDX lol yeah, the codesandbox look good for me... and your above code is unreadable. BTW, I saw you call addbuttonMenu twice for ToolKitProvider and BootstrapTable, I will suggest you call once like:

class Test extends React.Component {
  constructor() {
    this.columns = addbuttonMenu(columns)
  }
  render() {
      <ToolkitProvider ... columns={ .this.columns }>
          .....
         <BootstrapTable { ...props.baseProps } /> .  <<<< don't give column props here again
      </ToolkitProvider>
  }
}
AllenFang commented 4 years ago

BTW, I still can not reproduce this issue. so please show me an online case, thanks!

CACDX commented 4 years ago

Sorry for the code, we are begginers in react. I looked the codesandbox, and I modified something and now it's don't look good, that look has my project.

Edit silly-violet-61k8h

The idea is get the columns of a context, that it's be initialice with a local storage that contains the columns if exists, if not will be created the local storage. We want the users can hide columns because are a lot of columns and they don't fit on the screen. For this, we made a component with toggles buttons for each column.

AllenFang commented 4 years ago

@CACDX seems like react context can't not consume the value which contain a function. if you print the columns props before rendering, you will find the formatter method is disappear