ag-grid
Version: 
Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components
192 lines (155 loc) • 6.68 kB
text/typescript
import {AgCheckbox} from "../../widgets/agCheckbox";
import {BeanStub} from "../../context/beanStub";
import {PostConstruct, Autowired} from "../../context/context";
import {ColumnApi} from "../../columnController/columnApi";
import {GridApi} from "../../gridApi";
import {Events} from "../../events";
import {EventService} from "../../eventService";
import {IRowModel} from "../../interfaces/iRowModel";
import {Constants} from "../../constants";
import {Column} from "../../entities/column";
import {RowNode} from "../../entities/rowNode";
import {SelectionController} from "../../selectionController";
import {GridOptionsWrapper} from "../../gridOptionsWrapper";
export class SelectAllFeature extends BeanStub {
     private gridApi: GridApi;
     private columnApi: ColumnApi;
     private eventService: EventService;
     private rowModel: IRowModel;
     private selectionController: SelectionController;
     private gridOptionsWrapper: GridOptionsWrapper;
    private cbSelectAllVisible = false;
    private processingEventFromCheckbox = false;
    private column: Column;
    private filteredOnly: boolean;
    private cbSelectAll: AgCheckbox;
    constructor(cbSelectAll: AgCheckbox, column: Column) {
        super();
        this.cbSelectAll = cbSelectAll;
        this.column = column;
        let colDef = column.getColDef();
        this.filteredOnly = colDef ? !!colDef.headerCheckboxSelectionFilteredOnly : false;
    }
    
    private postConstruct(): void {
        this.showOrHideSelectAll();
        this.addDestroyableEventListener(this.eventService, Events.EVENT_DISPLAYED_COLUMNS_CHANGED, this.showOrHideSelectAll.bind(this));
        this.addDestroyableEventListener(this.eventService, Events.EVENT_SELECTION_CHANGED, this.onSelectionChanged.bind(this));
        this.addDestroyableEventListener(this.eventService, Events.EVENT_MODEL_UPDATED, this.onModelChanged.bind(this));
        this.addDestroyableEventListener(this.cbSelectAll, AgCheckbox.EVENT_CHANGED, this.onCbSelectAll.bind(this));
    }
    private showOrHideSelectAll(): void {
        this.cbSelectAllVisible = this.isCheckboxSelection();
        this.cbSelectAll.setVisible(this.cbSelectAllVisible);
        if (this.cbSelectAllVisible) {
            // in case user is trying this feature with the wrong model type
            this.checkRightRowModelType();
            // make sure checkbox is showing the right state
            this.updateStateOfCheckbox();
        }
    }
    private onModelChanged(): void {
        if (!this.cbSelectAllVisible) { return; }
        this.updateStateOfCheckbox();
    }
    private onSelectionChanged(): void {
        if (!this.cbSelectAllVisible) { return; }
        this.updateStateOfCheckbox();
    }
    private getNextCheckboxState(selectionCount: SelectionCount): boolean {
        if (selectionCount.selected===0 && selectionCount.notSelected===0) {
            // if no rows, always have it unselected
            return false;
        } else if (selectionCount.selected>0 && selectionCount.notSelected>0) {
            // if mix of selected and unselected, this is the tri-state
            return null;
        } else if (selectionCount.selected>0) {
            // only selected
            return true;
        } else {
            // nothing selected
            return false;
        }
    }
    private updateStateOfCheckbox(): void {
        if (this.processingEventFromCheckbox) { return; }
        this.processingEventFromCheckbox = true;
        let selectionCount = this.getSelectionCount();
        let allSelected = this.getNextCheckboxState(selectionCount);
        this.cbSelectAll.setSelected(allSelected);
        this.processingEventFromCheckbox = false;
    }
    private getSelectionCount(): SelectionCount {
        let selectedCount = 0;
        let notSelectedCount = 0;
        let callback = (node: RowNode) => {
            if (node.isSelected()) {
                selectedCount++;
            } else if (!node.selectable) {
                // don't count non-selectable nodes!
            } else {
                notSelectedCount++;
            }
        };
        if (this.filteredOnly) {
            this.gridApi.forEachNodeAfterFilter(callback);
        } else {
            this.gridApi.forEachNode(callback);
        }
        return {
            notSelected: notSelectedCount,
            selected: selectedCount
        };
    }
    private checkRightRowModelType(): void {
        let rowModelType = this.rowModel.getType();
        let rowModelMatches = rowModelType===Constants.ROW_MODEL_TYPE_CLIENT_SIDE;
        if (!rowModelMatches) {
            console.log(`ag-Grid: selectAllCheckbox is only available if using normal row model, you are using ${rowModelType}`);
        }
    }
    private onCbSelectAll(): void {
        if (this.processingEventFromCheckbox) { return; }
        if (!this.cbSelectAllVisible) { return; }
        let value = this.cbSelectAll.isSelected();
        if (value) {
            this.selectionController.selectAllRowNodes(this.filteredOnly);
        } else {
            this.selectionController.deselectAllRowNodes(this.filteredOnly);
        }
    }
    private isCheckboxSelection(): boolean {
        let result = this.column.getColDef().headerCheckboxSelection;
        if (typeof result === 'function') {
            let func = <(params: any)=>boolean> result;
            result = func({
                column: this.column,
                colDef: this.column.getColDef(),
                columnApi: this.columnApi,
                api: this.gridApi
            });
        }
        if (result) {
            if (this.gridOptionsWrapper.isRowModelServerSide()) {
                console.warn('headerCheckboxSelection is not supported for Server Side Row Model');
                return false;
            }
            if (this.gridOptionsWrapper.isRowModelInfinite()) {
                console.warn('headerCheckboxSelection is not supported for Infinite Row Model');
                return false;
            }
            if (this.gridOptionsWrapper.isRowModelViewport()) {
                console.warn('headerCheckboxSelection is not supported for Viewport Row Model');
                return false;
            }
            // otherwise the row model is compatible, so return true
            return true;
        } else {
            return false;
        }
    }
}
interface SelectionCount {
    selected: number;
    notSelected: number;
}