2017-10-06 3 views
0

Nous allons implémenter un columnpicker et actuellement la seule idée que j'ai est d'implémenter un ColumnPickableList qui enveloppe une liste. Cela contiendrait également une liste de cases à cocher qui permettront à l'utilisateur de cacher une colonne.Existe-t-il un moyen simple de mettre en œuvre un sélecteur de colonne pour une liste?

Mais avant que j'y aille, je me demandais juste si je réinviterais la roue et s'il y a une approche plus simple pour résoudre ce problème?

Répondre

2

Pas de manière plus simple. Vous devrez implémenter votre propre composant List pour cela

0

Je suis sur ce sujet depuis que j'ai du mal à faire ce travail. Peut-être que c'est parce que j'ai choisi de créer un wrapper qui filtre les enfants à afficher. Donc, de manière thématique, cette approche ne met pas en œuvre sa propre liste.

J'ai fait un brouillon naïf que j'espérais fonctionner, mais il ne parvient pas à rendre les enfants à nouveau, même s'ils sont modifiés/filtrés dans le composant parent. Le fichier console.log (..) dans la fonction render() de ColumnPickableList imprime les enfants/accessoires corrects, mais les enfants ne mettent pas à jour/restituent. Des indices quant à pourquoi? Cette approche est-elle trop naïve?

Voici donc le projet actuel:

ColumnPicker.js

import React, { PropTypes } from 'react'; 

import Checkbox from 'material-ui/Checkbox'; 

export default class ColumnPicker extends React.Component { 

    constructor(props) { 
    super(props); 
    this.onCheck = this.onCheck.bind(this); 
    } 

    onCheck(column, isChecked) { 
    return this.props.onCheckboxChanged(column, isChecked); 
    } 

    renderCheckbox(column, onCheck) { 
    const disabled = (column.source === 'id'); 
    return (<Checkbox key={column.source} label={column.source.toUpperCase()} onCheck={(event, checked) => onCheck(column, checked)} defaultChecked disabled={disabled} />); 
    } 

    render() { 
    const columns = this.props.columns || []; 

    return (
     <div className="column-picker"> 
     {columns.map((column) => { 
      return this.renderCheckbox(column, this.onCheck); 
     })} 
     </div> 
    ); 
    } 
} 

ColumnPicker.propTypes = { 
    columns: PropTypes.array, 
    onCheckboxChanged: PropTypes.func, 
}; 

ColumnPicker.defaultProps = { 
    columns: [], // [{source: myField, checked: true} ...] 
}; 

ColumnPickableList.js:

import React, { PropTypes } from 'react'; 
import { connect } from 'react-redux'; 
import { List, Datagrid } from 'admin-on-rest'; 
import ColumnPicker from './ColumnPicker'; 

import { toggleColumnPickerStatusAction, initializeColumnPickerAction } from './actions'; 

export class ColumnPickableList extends React.Component { 

    componentWillMount() { 
    let columnSourceNames = []; 
    if (this.props.children) { 
     columnSourceNames = React.Children.map(this.props.children, (child) => { 
     return ({ source: child.props.source, checked: true }); 
     }); 
    } 
    const columnsDisplayed = columnSourceNames.filter((column) => column.source); 
    this.props.initializeColumnPicker(this.props.resource, columnsDisplayed); 
    } 

    shouldComponentUpdate(nextProps) { 
    const diff = nextProps.columnsDisplayed.filter((currentColumn) => { 
     return !this.props.columnsDisplayed.some((prevColumn) => { 
     return currentColumn.source === prevColumn.source && currentColumn.checked === prevColumn.checked; 
     }); 
    }); 

    return diff.length > 0; 
    } 

    removeHiddenColumns(children) { 
    return React.Children.map(children, (child) => { 
     if (!child.props.source) { 
     return child; 
     } 
     const column = this.props.columnsDisplayed.find((columnDisplayed) => { 
     return columnDisplayed.source === child.props.source; 
     }); 

     if (this.props.columnsDisplayed.length === 0 || (column && column.checked)) { 
     return React.cloneElement(child); 
     } 
     return null; 
    }); 
    } 

    render() { 
    const { children, ...rest } = this.props; 
    const displayedChildren = this.removeHiddenColumns(children); 
    console.log('Does it render? Rendering children', displayedChildren.map((child) => child.props.source)); 

    return (
     <div className="columnpickable-list"> 
     <ColumnPicker columns={this.props.columnsDisplayed} onCheckboxChanged={this.props.handleCheckboxChanged} /> 
     <List {...rest}> 
      <Datagrid> 
      {displayedChildren} 
      </Datagrid> 
     </List> 
     </div> 
    ); 
    } 
} 

ColumnPickableList.propTypes = { 
    resource: PropTypes.string, 
    columnsDisplayed: PropTypes.array, 
    children: PropTypes.node, 
    initializeColumnPicker: PropTypes.func, 
    handleCheckboxChanged: PropTypes.func, 
}; 

ColumnPickableList.defaultProps = { 
    columnsDisplayed: [], 
}; 


function mapStateToProps(state) { 
    return { 
    columnsDisplayed: state.columnsDisplayed || [], 
    }; 
} 

actions.js:

export const actions = { 
    INIT_COLUMNPICKER: 'INIT_COLUMNPICKER', 
    TOGGLE_COLUMNPICKER_STATUS: 'UPDATE_COLUMNPICKER_STATUS', 
    UPDATE_COLUMNPICKER_STATUSES: 'UPDATE_COLUMNPICKER_STATUSES', 
} 


export function initializeColumnPickerAction(resource, columns) { 
    return { 
    type: actions.INIT_COLUMNPICKER, 
    columns, 
    meta: { resource }, 
    }; 
} 


export function toggleColumnPickerStatusAction(column) { 
    return { 
    type: actions.TOGGLE_COLUMNPICKER_STATUS, 
    column, 
    }; 
} 

reducers.js:

import { actions } from './actions'; 

function columnPickerReducer(state = [], action) { 
    switch (action.type) { 
    case actions.INIT_COLUMNPICKER: { 
     console.log('Init columnopicker reducer'); 
     return action.columns; 
    } 
    case actions.TOGGLE_COLUMNPICKER_STATUS: { 
     const columns = state.map((column) => { 
     if (column.source === action.column.source) { 
      return { ...column, checked: !column.checked }; 
     } 
     return column; 
     }); 
     return columns; 
    } 
    default: 
     return state; 
    } 
} 

export default columnPickerReducer; 

Exemple d'extrait de composant parent:

... 

<ColumnPickableList title="SillyStuff" {...props}> 
    <TextField source="id" /> 
    <TextField source="NAME" /> 
    <TextField source="SILLY_NAME" /> 
    <TextField source="CHANGED_BY" /> 
    <DateField source="CHANGED_TS" showTime /> 
    <EditButton /> 
    <DeleteButton /> 
</ColumnPickableList> 
... 
+0

est-ce qui précède un bug? Ne devrait-il pas être possible de manipuler les enfants comme ça? @Gildas – activist

+0

Avez-vous essayé la fonction comme un modèle enfant ici? Voir https://marmelab.com/admin-on-rest/Authorization.html#restricting-access-to-fields-and-inputs. Dans la version 2.0.0, vous ne devrez pas utiliser authClient pour que cela fonctionne. En attendant, il suffit de mettre en place un mannequin si nécessaire – Gildas