Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Header as CheckBox to Select all rows in table. #822

Open
neerajmangal opened this issue Jul 20, 2018 · 4 comments
Open

Custom Header as CheckBox to Select all rows in table. #822

neerajmangal opened this issue Jul 20, 2018 · 4 comments

Comments

@neerajmangal
Copy link

neerajmangal commented Jul 20, 2018

Griddle version

1.13.1

Expected Behavior

I have a customHeaderComponent which is a check box and CustomColumnComponent which has a checkBox for each row in table.

I want to select Header checkbox to select all rows in the table.

screen shot 2018-07-20 at 8 17 44 pm

Actual Behavior

Could not figure out a way to achieve it. Can someone please help on this?
Also how I can restrict users to select more than one row

screen shot 2018-07-20 at 8 14 45 pm

@neerajmangal neerajmangal changed the title Customer Header CheckBox and To Sel Customer Header CheckBox and To Select all rows. Jul 20, 2018
@neerajmangal neerajmangal changed the title Customer Header CheckBox and To Select all rows. Custom Header as CheckBox to Select all rows in table. Jul 20, 2018
@dahlbyk
Copy link
Contributor

dahlbyk commented Jul 20, 2018

Please share what you have tried, or some sort of starter code so we can point you in the right direction!

Also how I can restrict users to select more than one row

Not sure what you mean by this?

@neerajmangal
Copy link
Author

Thanks @dahlbyk for taking a look.
This is I have been trying.
I am trying to create a common component for TableView using griddle which other component in my application will use. Below is the CustomTableView I have created.

const rowDataSelector = (state, { griddleKey }) => {
    return state
        .get('data')
        .find(rowMap => rowMap.get('griddleKey') === griddleKey)
        .toJSON();
};

/** use griddle's connect function only*/
const enhancedWithRowData = utils.connect((state, props) => {
    return {
        // rowData will be available into customComponents
        rowData: rowDataSelector(state, props)
    };
});

const getAllRowsData = (state, props) => {
    return state.get('data').toJSON();
};

const enhanceedWithTableData = utils.connect((state, props) =>{
    return {
      allRowsData: getAllRowsData(state, props)
    };
 });

/* This seems to be a stateless function but as we are using "ref" in Griddle
*  It will throw error if converted to pure/smart component.
*/
class CustomTableView extends React.Component {
  constructor(props) {
      super(props);
      /*Default fallback to CustomFilter in case Platform/Tool
       specific Filter is not provided.*/
      this.customFilters = props.tblFilters ? props.tblFilters : CustomFilter;
  }
  render() {
    return (
    <Griddle
      ref="Griddle"
      useCustomFilterComponent
      /** This storeKey is very important here, without providing it
       * Custom Component will not be able to connect to global store.   
       * https://github.com/GriddleGriddle/Griddle/issues/626
       * https://github.com/GriddleGriddle/Griddle/issues/647 
       */
      storeKey="griddle"
      customFilterComponent={this.customFilters}
      styleConfig={styleConfig}
      data={this.props.data}
      showSettings={false}
      sortProperties={this.props.sortProperties}
      pageProperties={{
        currentPage: 1,
        pageSize: 10,
        recordCount: 10,
        useGriddleStyles: false
      }}
      components={
          /* Make sure your custom filter component pass setFilter to children*/
          { Filter: (filter) =>
                  this.props.tblFilters ? <this.props.tblFilters {...this.props} filter={filter.setFilter}/>
                      : <CustomFilter {...this.props} filterRef={filter.setFilter}/>,
              Layout: Layout
          } //SettingsToggle: CustomFilter //TableContainer: CustomTableComponent
      }
      plugins={[plugins.LocalPlugin]}
    >
      <RowDefinition>
        {this.props.columns.map((column, i) => {
            let columnComponent;
            let CustomHeader;
            if (typeof column.CustomComponent !== 'undefined') {
                columnComponent = enhancedWithRowData(column.CustomComponent);
            } 
            if (typeof column.CustomHeader !== 'undefined') {
              CustomHeader = enhanceedWithTableData(column.CustomHeader);
            } 
            return(
              <ColumnDefinition
                key={i}
                id={column.key}
                title={column.title}
                width={column.width}
                customComponent={columnComponent}
                customHeadingComponent={CustomHeader}
                //sortable={column.sortable}
                {...this.props}
              />
            );
          }
        )}
      </RowDefinition>
    </Griddle>
    );
  }
}

CustomTableView.propTypes = {
    /* Table Data to be rendered*/
    data: PropTypes.array.isRequired,
    /* Table Columns to be rendered and mapped to data*/
    columns: PropTypes.array.isRequired,
    /* Any shortProperties for pagination*/
    sortProperties: PropTypes.array,
    /* Custom filters for table data*/
    tblFilters: PropTypes.func
};

export default CustomTableView;

The Table Columns are defined like this.

export const ServerlessTableDataColumns = [
    {
        title: "Select",
        key: "IsSelected",
        width: 20,
        sortable: false,
        CustomComponent: RowSelection,
        CustomHeader: SelectAllRow
    },
    {
        title: 'Function Name',
        key: 'functionName',
        width: 100,
        sortable:true
    },
    {
        title: 'Runtime',
        key: 'runtime',
        minWidth: 50,
        sortable: true,
        divider: true
    },
    {
        title: 'Namespace',
        key: 'namespace',
        minWidth: 50,
        sortable: true
    },
    {
        title: 'Web Action',
        key: 'webAction',
        minWidth: 20,
        sortable: true,
        CustomComponent: ToggleWebAction
    },
    {
        title: 'Shared',
        key: 'shared',
        minWidth: 20,
        sortable: true,
        CustomComponent: togglePublish
    },
    {
        title: 'Version',
        key: 'version',
        minWidth: 20,
        sortable: true
    },
    {
        title: 'Delete',
        key: 'delete',
        minWidth: 20,
        sortable: false,
        CustomComponent: DeleteFunction
    },
    {
        title: 'More',
        key: 'more',
        minWidth: 20,
        sortable: false,
        CustomComponent: ExtendedActions
    }
];

As you can see first colum is having customHeadingComponent as CustomHeader: SelectAllRow and customComponent as columnComponent:RowSelection I passed in to .

// SelectAllRow CustomHeader Component for header checkBox.

export const SelectAllRow = (props) => {
    function onSelectAllRow(e) {
        console.log("All rows selected", e);
        /*
        if (props.allRowsData !== null) {
            props.allRowsData.forEach(
                (data, index) => {
                    let RowData = {
                        value: e,
                        griddleKey: index,
                        rowData: data
                    };
                    RowSelection(RowData);
                }
            );
        }
        */
    }
    return (
        <div style={{ paddingTop: "4px" }}>
            <Checkbox
                label=""
                onChange={onSelectAllRow}
            />
        </div>);
};

In SelectAllRow i am not able to figure out how I can pass the onChange event to all table rows.
Please let me know how I can do this or is there anything I am missing.
Let me know if more information is needed, i will provide that.

Regarding restriction on user to select more than one row, I mean to say is there any property I can pass to Griddle to not allow multiple row selection at a time (i.e user can select only one row at a time or all rows by header checkbox).

Thanks.

@dahlbyk
Copy link
Contributor

dahlbyk commented Jul 23, 2018

OK, based on your commented code in onSelectAllRow I think you need to shift how you're thinking about selection. You're not going to be able to make changes to props.allRowsData and expect the app to update accordingly; you need to approach this as a state change. Since you have a CustomTableView wrapper around your <Griddle />, you could have your which-row(s)-selected state live there (passed down into RowSelection and SelectAllRow). Or it might be easier to use Griddle's internal Redux store, similar to PositionPlugin.

@neerajmangal
Copy link
Author

Thanks @dahlbyk , I moved to the first approach and make it working somewhat.
Here are the changes I made in RowSelection and SelectAllRows.
Basically I have a state enabled in my global store and based on that update the state of all checkboxes in RowSelection.

class RowSelection extends Component {
    constructor(props) {
        super(props);
        this.props = props;
        this.onRowSelection = this.onRowSelection.bind(this);
        this.state = {
            isSelected: this.props.isAllChecked
        };   
    }

    onRowSelection(e) {
        console.log("value, propsValue, GriddleKey, rowData",
         e, this.props.vale, this.props.griddleKey, this.props.rowData);
        this.setState({
            isSelected: e
        });
        /*
        this.dispatch(updateWebActionStatus(this.props.cellProperties.userDetails.ldapId, 
            this.props.cellProperties.token,
            this.props.rowData, !this.props.value));
            */
    }
    
    componentWillReceiveProps(nextProps) {
        console.log(nextProps);
        this.setState({
            isSelected: nextProps.isAllChecked
        });
    }

    render() {
        return (
            <Checkbox
                label=""
                value={this.state.isSelected}
                checked={this.state.isSelected}
                onChange={this.onRowSelection}
            />
        );
    }
}

const mapStateToProps = (state) => {
    return {
        isAllChecked: state.platforms.serverless.isAllChecked
    };
};

export default connect(mapStateToProps)(RowSelection);
class SelectAllRow extends Component {
    constructor(props) {
        super(props);
        this.props = props;
        this.dispatch = this.props.cellProperties.dispatch;
        this.onAllRowSelection = this.onAllRowSelection.bind(this);
        this.state = {
            isSelected: this.props.isAllChecked
        };   
    }

    onAllRowSelection(e) {
        this.dispatch(selectAll(e)); 
        this.setState({
            isSelected: e
        });
        /*
        this.dispatch(updateWebActionStatus(this.props.cellProperties.userDetails.ldapId, 
            this.props.cellProperties.token,
            this.props.rowData, !this.props.value));
            */
    }
    
    componentWillReceiveProps(nextProps) {
        console.log(nextProps);
        this.setState({
            isSelected: nextProps.isAllChecked
        });
    }

    render() {
        return (
            <Checkbox
                label=""
                value={this.state.isSelected}
                checked={this.state.isSelected}
                onChange={this.onAllRowSelection}
            />
        );
    }
}

const mapStateToProps = (state) => {
    return {
        isAllChecked: state.platforms.serverless.isAllChecked
    };
};

export default connect(mapStateToProps)(SelectAllRow);

With this I am able to see all checkboxes selected when header checkbox is selected. I am now looking for better solution to update the internal Griddle State for more features for this checkbox flow and will check position plugin for reference to do that.

Thanks for the guidance. I will post once I am done with that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants