Home Reference Source Repository

src/SelectableTable.js

/**
 * @file SelectableTable
 * @author leon([email protected])
 */

import React, {Component, PropTypes} from 'react';
import Table from './Table';
import SelectorColumn from './table/SelectorColumn';

function getNextSelectedRowData(multiple, dataSource, current, action, rowIndex) {

    if (!multiple) {
        return [rowIndex];
    }

    if (action === 'selectAll') {
        return dataSource.map((_, index) => index);
    }

    if (action === 'unselectAll') {
        return [];
    }

    let selected = action === 'select'
        ? current.concat(rowIndex).sort()
        : current.filter(function (row) {
            return row !== rowIndex;
        });

    return selected;

}

export default class SelectableTable extends Component {

    constructor(props) {

        super(props);

        this.getSelected = this.getSelected.bind(this);
        this.isAllRowsSelected = this.isAllRowsSelected.bind(this);
        this.isRowSelected = this.isRowSelected.bind(this);
        this.onSelect = this.onSelect.bind(this);
        this.onSelectAll = this.onSelectAll.bind(this);

        this.state = {
            selected: this.props.selected
        };

    }

    componentWillReceiveProps(props) {

        if (!this.props.onSelect) {
            this.setState({
                selected: props.selected
            });
        }

    }

    onSelect(rowIndex) {
        this.onRowSelectorClick(
            this.isRowSelected(rowIndex) ? 'unselect' : 'select',
            rowIndex
        );
    }

    onSelectAll() {
        this.onRowSelectorClick(
            this.isAllRowsSelected() ? 'unselectAll' : 'selectAll'
        );
    }

    onRowSelectorClick(action, rowIndex) {

        const {
            onSelect,
            dataSource,
            multiple
        } = this.props;

        let selected = this.getSelected();

        selected = getNextSelectedRowData(
            multiple,
            dataSource,
            selected,
            action,
            rowIndex
        );

        if (onSelect) {
            onSelect({
                selected,
                target: this
            });
            return;
        }

        this.setState({
            selected
        });

    }

    getSelected() {
        const {state, props} = this;
        const {onSelect} = props;
        const {selected} = onSelect ? props : state;
        return selected;
    }

    isRowSelected(rowIndex) {
        const selected = this.getSelected();
        return selected.indexOf(rowIndex) !== -1;
    }

    isAllRowsSelected() {
        const selected = this.getSelected();
        return selected.length === this.props.dataSource.length;
    }

    render() {

        const {children, multiple, ...rest} = this.props;

        return (
            <Table {...rest}>
                <SelectorColumn
                    isSelected={this.isRowSelected}
                    isAllSelected={this.isAllRowsSelected}
                    multiple={multiple}
                    onSelect={this.onSelect}
                    onSelectAll={this.onSelectAll} />
                {children}
            </Table>
        );

    }

}

SelectableTable.displayName = 'SelectableTable';

SelectableTable.propTypes = {
    ...Table.propTypes,
    multiple: PropTypes.bool.isRequired,
    onSelect: PropTypes.func,
    selected: PropTypes.arrayOf(PropTypes.number).isRequired
};

SelectableTable.defaultProps = {
    ...Table.defaultProps,
    multiple: true,
    selected: []
};