UNPKG

23.3 kBPlain TextView Raw
1import {ColumnGroupChild} from "./columnGroupChild";
2import {OriginalColumnGroupChild} from "./originalColumnGroupChild";
3import {
4 AbstractColDef,
5 BaseColDefParams,
6 ColDef,
7 ColSpanParams,
8 IAggFunc,
9 IsColumnFunc,
10 IsColumnFuncParams, RowSpanParams
11} from "./colDef";
12import {EventService} from "../eventService";
13import {Utils as _} from "../utils";
14import {Autowired, PostConstruct} from "../context/context";
15import {GridOptionsWrapper} from "../gridOptionsWrapper";
16import {ColumnUtils} from "../columnController/columnUtils";
17import {RowNode} from "./rowNode";
18import {IFrameworkFactory} from "../interfaces/iFrameworkFactory";
19import {IEventEmitter} from "../interfaces/iEventEmitter";
20import {ColumnEvent, ColumnEventType} from "../events";
21import {ColumnApi} from "../columnController/columnApi";
22import {GridApi} from "../gridApi";
23import {ColumnGroup} from "./columnGroup";
24
25// Wrapper around a user provide column definition. The grid treats the column definition as ready only.
26// This class contains all the runtime information about a column, plus some logic (the definition has no logic).
27// This class implements both interfaces ColumnGroupChild and OriginalColumnGroupChild as the class can
28// appear as a child of either the original tree or the displayed tree. However the relevant group classes
29// for each type only implements one, as each group can only appear in it's associated tree (eg OriginalColumnGroup
30// can only appear in OriginalColumn tree).
31export class Column implements ColumnGroupChild, OriginalColumnGroupChild, IEventEmitter {
32
33 // + renderedHeaderCell - for making header cell transparent when moving
34 public static EVENT_MOVING_CHANGED = 'movingChanged';
35 // + renderedCell - changing left position
36 public static EVENT_LEFT_CHANGED = 'leftChanged';
37 // + renderedCell - changing width
38 public static EVENT_WIDTH_CHANGED = 'widthChanged';
39 // + renderedCell - for changing pinned classes
40 public static EVENT_LAST_LEFT_PINNED_CHANGED = 'lastLeftPinnedChanged';
41 public static EVENT_FIRST_RIGHT_PINNED_CHANGED = 'firstRightPinnedChanged';
42 // + renderedColumn - for changing visibility icon
43 public static EVENT_VISIBLE_CHANGED = 'visibleChanged';
44 // + every time the filter changes, used in the floating filters
45 public static EVENT_FILTER_CHANGED = 'filterChanged';
46 // + renderedHeaderCell - marks the header with filter icon
47 public static EVENT_FILTER_ACTIVE_CHANGED = 'filterActiveChanged';
48 // + renderedHeaderCell - marks the header with sort icon
49 public static EVENT_SORT_CHANGED = 'sortChanged';
50
51 public static EVENT_MENU_VISIBLE_CHANGED = 'menuVisibleChanged';
52
53 // + toolpanel, for gui updates
54 public static EVENT_ROW_GROUP_CHANGED = 'columnRowGroupChanged';
55 // + toolpanel, for gui updates
56 public static EVENT_PIVOT_CHANGED = 'columnPivotChanged';
57 // + toolpanel, for gui updates
58 public static EVENT_VALUE_CHANGED = 'columnValueChanged';
59
60 public static PINNED_RIGHT = 'right';
61 public static PINNED_LEFT = 'left';
62
63 public static SORT_ASC = 'asc';
64 public static SORT_DESC = 'desc';
65
66 @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
67 @Autowired('columnUtils') private columnUtils: ColumnUtils;
68 @Autowired('frameworkFactory') private frameworkFactory: IFrameworkFactory;
69 @Autowired('columnApi') private columnApi: ColumnApi;
70 @Autowired('gridApi') private gridApi: GridApi;
71
72 private colDef: ColDef;
73 private colId: any;
74
75 private actualWidth: any;
76
77 private visible: any;
78 private pinned: string;
79 private left: number;
80 private oldLeft: number;
81 private aggFunc: string | IAggFunc;
82 private sort: string;
83 private sortedAt: number;
84 private moving = false;
85 private menuVisible = false;
86
87 // we copy this from col def, as if it's value changes are column is created,
88 // it will break the logic in the column controller
89 private lockPosition: boolean;
90 private lockPinned: boolean;
91 private lockVisible: boolean;
92
93 private lastLeftPinned: boolean;
94 private firstRightPinned: boolean;
95
96 private minWidth: number;
97 private maxWidth: number;
98
99 private filterActive = false;
100
101 private eventService: EventService = new EventService();
102
103 private fieldContainsDots: boolean;
104 private tooltipFieldContainsDots: boolean;
105
106 private rowGroupActive = false;
107 private pivotActive = false;
108 private aggregationActive = false;
109
110 private primary: boolean;
111
112 private parent: ColumnGroup;
113
114 constructor(colDef: ColDef, colId: String, primary: boolean) {
115 this.colDef = colDef;
116 this.visible = !colDef.hide;
117 this.sort = colDef.sort;
118 this.sortedAt = colDef.sortedAt;
119 this.colId = colId;
120 this.primary = primary;
121 this.lockPosition = colDef.lockPosition === true;
122 this.lockPinned = colDef.lockPinned === true;
123 this.lockVisible = colDef.lockVisible === true;
124 }
125
126 public isLockPosition(): boolean {
127 return this.lockPosition;
128 }
129
130 public isLockVisible(): boolean {
131 return this.lockVisible;
132 }
133
134 public isLockPinned(): boolean {
135 return this.lockPinned;
136 }
137
138 public setParent(parent: ColumnGroup): void {
139 this.parent = parent;
140 }
141
142 public getParent(): ColumnGroup {
143 return this.parent;
144 }
145
146 // this is done after constructor as it uses gridOptionsWrapper
147 @PostConstruct
148 public initialise(): void {
149 this.setPinned(this.colDef.pinned);
150
151 let minColWidth = this.gridOptionsWrapper.getMinColWidth();
152 let maxColWidth = this.gridOptionsWrapper.getMaxColWidth();
153
154 if (this.colDef.minWidth) {
155 this.minWidth = this.colDef.minWidth;
156 } else {
157 this.minWidth = minColWidth;
158 }
159
160 if (this.colDef.maxWidth) {
161 this.maxWidth = this.colDef.maxWidth;
162 } else {
163 this.maxWidth = maxColWidth;
164 }
165
166 this.actualWidth = this.columnUtils.calculateColInitialWidth(this.colDef);
167
168 let suppressDotNotation = this.gridOptionsWrapper.isSuppressFieldDotNotation();
169 this.fieldContainsDots = _.exists(this.colDef.field) && this.colDef.field.indexOf('.')>=0 && !suppressDotNotation;
170 this.tooltipFieldContainsDots = _.exists(this.colDef.tooltipField) && this.colDef.tooltipField.indexOf('.')>=0 && !suppressDotNotation;
171
172 this.validate();
173 }
174
175 public isEmptyGroup(): boolean {
176 return false;
177 }
178
179 public isRowGroupDisplayed(colId: string): boolean {
180 if (_.missing(this.colDef) || _.missing(this.colDef.showRowGroup)) { return false; }
181
182 let showingAllGroups = this.colDef.showRowGroup === true;
183 let showingThisGroup = this.colDef.showRowGroup === colId;
184
185 return showingAllGroups || showingThisGroup;
186 }
187
188 public getUniqueId(): string {
189 return this.getId();
190 }
191
192 public isPrimary(): boolean {
193 return this.primary;
194 }
195
196 public isFilterAllowed(): boolean {
197 return this.primary && !this.colDef.suppressFilter;
198 }
199
200 public isFieldContainsDots(): boolean {
201 return this.fieldContainsDots;
202 }
203
204 public isTooltipFieldContainsDots(): boolean {
205 return this.tooltipFieldContainsDots;
206 }
207
208 private validate(): void {
209
210 let colDefAny = <any> this.colDef;
211
212 if (!this.gridOptionsWrapper.isEnterprise()) {
213 let itemsNotAllowedWithoutEnterprise =
214 ['enableRowGroup','rowGroup','rowGroupIndex','enablePivot','pivot','pivotIndex','aggFunc'];
215 itemsNotAllowedWithoutEnterprise.forEach( item => {
216 if (_.exists(colDefAny[item])) {
217 console.warn(`ag-Grid: ${item} is only valid in ag-Grid-Enterprise, your column definition should not have ${item}`);
218 }
219 });
220 }
221
222 if (this.gridOptionsWrapper.isTreeData()) {
223 let itemsNotAllowedWithTreeData =
224 ['enableRowGroup','rowGroup','rowGroupIndex','enablePivot','pivot','pivotIndex'];
225 itemsNotAllowedWithTreeData.forEach( item => {
226 if (_.exists(colDefAny[item])) {
227 console.warn(`ag-Grid: ${item} is not possible when doing tree data, your column definition should not have ${item}`);
228 }
229 });
230 }
231
232 if (_.exists(this.colDef.width) && typeof this.colDef.width !== 'number') {
233 console.warn('ag-Grid: colDef.width should be a number, not ' + typeof this.colDef.width);
234 }
235
236 if (_.get(this, 'colDef.cellRendererParams.restrictToOneGroup', null)) {
237 console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.restrictToOneGroup is deprecated. You should use showRowGroup');
238 }
239
240 if (_.get(this, 'colDef.cellRendererParams.keyMap', null)) {
241 console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.keyMap is deprecated. You should use colDef.keyCreator');
242 }
243
244 if (_.get(this, 'colDef.cellRendererParams.keyMap', null)) {
245 console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.keyMap is deprecated. You should use colDef.keyCreator');
246 }
247
248 if (colDefAny.floatingCellRenderer) {
249 console.warn('ag-Grid: since v11, floatingCellRenderer is now pinnedRowCellRenderer');
250 this.colDef.pinnedRowCellRenderer = colDefAny.floatingCellRenderer;
251 }
252 if (colDefAny.floatingRendererFramework) {
253 console.warn('ag-Grid: since v11, floatingRendererFramework is now pinnedRowCellRendererFramework');
254 this.colDef.pinnedRowCellRendererFramework = colDefAny.floatingRendererFramework;
255 }
256 if (colDefAny.floatingRendererParams) {
257 console.warn('ag-Grid: since v11, floatingRendererParams is now pinnedRowCellRendererParams');
258 this.colDef.pinnedRowCellRendererParams = colDefAny.floatingRendererParams;
259 }
260 if (colDefAny.floatingValueFormatter) {
261 console.warn('ag-Grid: since v11, floatingValueFormatter is now pinnedRowValueFormatter');
262 this.colDef.pinnedRowValueFormatter = colDefAny.floatingValueFormatter;
263 }
264 if (colDefAny.cellFormatter) {
265 console.warn('ag-Grid: since v12, cellFormatter is now valueFormatter');
266 if (_.missing(this.colDef.valueFormatter)) {
267 this.colDef.valueFormatter = colDefAny.cellFormatter;
268 }
269 }
270
271 if (colDefAny.headerCellTemplate) {
272 console.warn('ag-Grid: since v15, headerCellTemplate is gone, use header component instead.');
273 }
274 if (colDefAny.headerCellRenderer) {
275 console.warn('ag-Grid: since v15, headerCellRenderer is gone, use header component instead.');
276 }
277
278 if (colDefAny.volatile) {
279 console.warn('ag-Grid: since v16, colDef.volatile is gone, please check refresh docs on how to refresh specific cells.');
280 }
281
282 }
283
284 public addEventListener(eventType: string, listener: Function): void {
285 this.eventService.addEventListener(eventType, listener);
286 }
287
288 public removeEventListener(eventType: string, listener: Function): void {
289 this.eventService.removeEventListener(eventType, listener);
290 }
291
292 private createIsColumnFuncParams(rowNode: RowNode): IsColumnFuncParams {
293 return {
294 node: rowNode,
295 data: rowNode.data,
296 column: this,
297 colDef: this.colDef,
298 context: this.gridOptionsWrapper.getContext(),
299 api: this.gridOptionsWrapper.getApi(),
300 columnApi: this.gridOptionsWrapper.getColumnApi()
301 };
302 }
303
304 public isSuppressNavigable(rowNode: RowNode): boolean {
305 // if boolean set, then just use it
306 if (typeof this.colDef.suppressNavigable === 'boolean') {
307 return <boolean> this.colDef.suppressNavigable;
308 }
309
310 // if function, then call the function to find out
311 if (typeof this.colDef.suppressNavigable === 'function') {
312 let params = this.createIsColumnFuncParams(rowNode);
313 let userFunc = <IsColumnFunc> this.colDef.suppressNavigable;
314 return userFunc(params);
315 }
316
317 return false;
318 }
319
320 public isCellEditable(rowNode: RowNode): boolean {
321
322 // only allow editing of groups if the user has this option enabled
323 if (rowNode.group && !this.gridOptionsWrapper.isEnableGroupEdit()) {
324 return false;
325 }
326
327 return this.isColumnFunc(rowNode, this.colDef.editable);
328 }
329
330 public isRowDrag(rowNode: RowNode): boolean {
331 return this.isColumnFunc(rowNode, this.colDef.rowDrag);
332 }
333
334 public isCellCheckboxSelection(rowNode: RowNode): boolean {
335 return this.isColumnFunc(rowNode, this.colDef.checkboxSelection);
336 }
337
338 public isSuppressPaste(rowNode: RowNode): boolean {
339 return this.isColumnFunc(rowNode, this.colDef ? this.colDef.suppressPaste : null);
340 }
341
342 public isResizable(): boolean {
343 let enableColResize = this.gridOptionsWrapper.isEnableColResize();
344 let suppressResize = this.colDef && this.colDef.suppressResize;
345 return enableColResize && !suppressResize;
346 }
347
348 private isColumnFunc(rowNode: RowNode, value: boolean | IsColumnFunc): boolean {
349 // if boolean set, then just use it
350 if (typeof value === 'boolean') {
351 return <boolean> value;
352 }
353
354 // if function, then call the function to find out
355 if (typeof value === 'function') {
356 let params = this.createIsColumnFuncParams(rowNode);
357 let editableFunc = <IsColumnFunc> value;
358 return editableFunc(params);
359 }
360
361 return false;
362 }
363
364 public setMoving(moving: boolean, source: ColumnEventType = "api"): void {
365 this.moving = moving;
366 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_MOVING_CHANGED, source));
367 }
368
369 private createColumnEvent(type: string, source: ColumnEventType): ColumnEvent {
370 return {
371 api: this.gridApi,
372 columnApi: this.columnApi,
373 type: type,
374 column: this,
375 columns: [this],
376 source: source
377 };
378 }
379
380 public isMoving(): boolean {
381 return this.moving;
382 }
383
384 public getSort(): string {
385 return this.sort;
386 }
387
388 public setSort(sort: string, source: ColumnEventType = "api"): void {
389 if (this.sort !== sort) {
390 this.sort = sort;
391 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_SORT_CHANGED, source));
392 }
393 }
394
395 public setMenuVisible(visible: boolean, source: ColumnEventType = "api"): void {
396 if (this.menuVisible !== visible) {
397 this.menuVisible = visible;
398 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_MENU_VISIBLE_CHANGED, source));
399 }
400 }
401
402 public isMenuVisible(): boolean {
403 return this.menuVisible;
404 }
405
406 public isSortAscending(): boolean {
407 return this.sort === Column.SORT_ASC;
408 }
409
410 public isSortDescending(): boolean {
411 return this.sort === Column.SORT_DESC;
412 }
413
414 public isSortNone(): boolean {
415 return _.missing(this.sort);
416 }
417
418 public isSorting(): boolean {
419 return _.exists(this.sort);
420 }
421
422 public getSortedAt(): number {
423 return this.sortedAt;
424 }
425
426 public setSortedAt(sortedAt: number): void {
427 this.sortedAt = sortedAt;
428 }
429
430 public setAggFunc(aggFunc: string | IAggFunc): void {
431 this.aggFunc = aggFunc;
432 }
433
434 public getAggFunc(): string | IAggFunc {
435 return this.aggFunc;
436 }
437
438 public getLeft(): number {
439 return this.left;
440 }
441
442 public getOldLeft(): number {
443 return this.oldLeft;
444 }
445
446 public getRight(): number {
447 return this.left + this.actualWidth;
448 }
449
450 public setLeft(left: number, source: ColumnEventType = "api") {
451 this.oldLeft = this.left;
452 if (this.left !== left) {
453 this.left = left;
454 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_LEFT_CHANGED, source));
455 }
456 }
457
458 public isFilterActive(): boolean {
459 return this.filterActive;
460 }
461
462 public setFilterActive(active: boolean, source: ColumnEventType = "api"): void {
463 if (this.filterActive !== active) {
464 this.filterActive = active;
465 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FILTER_ACTIVE_CHANGED, source));
466 }
467 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FILTER_CHANGED, source));
468 }
469
470 public setPinned(pinned: string|boolean): void {
471 if (pinned===true || pinned===Column.PINNED_LEFT) {
472 this.pinned = Column.PINNED_LEFT;
473 } else if (pinned===Column.PINNED_RIGHT) {
474 this.pinned = Column.PINNED_RIGHT;
475 } else {
476 this.pinned = null;
477 }
478 }
479
480 public setFirstRightPinned(firstRightPinned: boolean, source: ColumnEventType = "api"): void {
481 if (this.firstRightPinned !== firstRightPinned) {
482 this.firstRightPinned = firstRightPinned;
483 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FIRST_RIGHT_PINNED_CHANGED, source));
484 }
485 }
486
487 public setLastLeftPinned(lastLeftPinned: boolean, source: ColumnEventType = "api"): void {
488 if (this.lastLeftPinned !== lastLeftPinned) {
489 this.lastLeftPinned = lastLeftPinned;
490 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_LAST_LEFT_PINNED_CHANGED, source));
491 }
492 }
493
494 public isFirstRightPinned(): boolean {
495 return this.firstRightPinned;
496 }
497
498 public isLastLeftPinned(): boolean {
499 return this.lastLeftPinned;
500 }
501
502 public isPinned(): boolean {
503 return this.pinned === Column.PINNED_LEFT || this.pinned === Column.PINNED_RIGHT;
504 }
505
506 public isPinnedLeft(): boolean {
507 return this.pinned === Column.PINNED_LEFT;
508 }
509
510 public isPinnedRight(): boolean {
511 return this.pinned === Column.PINNED_RIGHT;
512 }
513
514 public getPinned(): string {
515 return this.pinned;
516 }
517
518 public setVisible(visible: boolean, source: ColumnEventType = "api"): void {
519 let newValue = visible===true;
520 if (this.visible !== newValue) {
521 this.visible = newValue;
522 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_VISIBLE_CHANGED, source));
523 }
524 }
525
526 public isVisible(): boolean {
527 return this.visible;
528 }
529
530 public getColDef(): ColDef {
531 return this.colDef;
532 }
533
534 public getColumnGroupShow(): string {
535 return this.colDef.columnGroupShow;
536 }
537
538 public getColId(): string {
539 return this.colId;
540 }
541
542 public getId(): string {
543 return this.getColId();
544 }
545
546 public getDefinition(): AbstractColDef {
547 return this.colDef;
548 }
549
550 public getActualWidth(): number {
551 return this.actualWidth;
552 }
553
554 private createBaseColDefParams(rowNode: RowNode): BaseColDefParams {
555 let params: BaseColDefParams = {
556 node: rowNode,
557 data: rowNode.data,
558 colDef: this.colDef,
559 column: this,
560 api: this.gridOptionsWrapper.getApi(),
561 columnApi: this.gridOptionsWrapper.getColumnApi(),
562 context: this.gridOptionsWrapper.getContext()
563 };
564 return params;
565 }
566
567 public getColSpan(rowNode: RowNode): number {
568 if (_.missing(this.colDef.colSpan)) {
569 return 1;
570 } else {
571 let params: ColSpanParams = this.createBaseColDefParams(rowNode);
572 let colSpan = this.colDef.colSpan(params);
573 // colSpan must be number equal to or greater than 1
574 if (colSpan > 1) {
575 return colSpan;
576 } else {
577 return 1;
578 }
579 }
580 }
581
582 public getRowSpan(rowNode: RowNode): number {
583 if (_.missing(this.colDef.rowSpan)) {
584 return 1;
585 } else {
586 let params: RowSpanParams = this.createBaseColDefParams(rowNode);
587 let rowSpan = this.colDef.rowSpan(params);
588 // rowSpan must be number equal to or greater than 1
589 if (rowSpan > 1) {
590 return rowSpan;
591 } else {
592 return 1;
593 }
594 }
595 }
596
597 public setActualWidth(actualWidth: number, source: ColumnEventType = "api"): void {
598 if (this.actualWidth !== actualWidth) {
599 this.actualWidth = actualWidth;
600 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_WIDTH_CHANGED, source));
601 }
602 }
603
604 public isGreaterThanMax(width: number): boolean {
605 if (this.maxWidth) {
606 return width > this.maxWidth;
607 } else {
608 return false;
609 }
610 }
611
612 public getMinWidth(): number {
613 return this.minWidth;
614 }
615
616 public getMaxWidth(): number {
617 return this.maxWidth;
618 }
619
620 public setMinimum(source: ColumnEventType = "api"): void {
621 this.setActualWidth(this.minWidth, source);
622 }
623
624 public setRowGroupActive(rowGroup: boolean, source: ColumnEventType = "api"): void {
625 if (this.rowGroupActive !== rowGroup) {
626 this.rowGroupActive = rowGroup;
627 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_ROW_GROUP_CHANGED, source));
628 }
629 }
630
631 public isRowGroupActive(): boolean {
632 return this.rowGroupActive;
633 }
634
635 public setPivotActive(pivot: boolean, source: ColumnEventType = "api"): void {
636 if (this.pivotActive !== pivot) {
637 this.pivotActive = pivot;
638 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_PIVOT_CHANGED, source));
639 }
640 }
641
642 public isPivotActive(): boolean {
643 return this.pivotActive;
644 }
645
646 public isAnyFunctionActive(): boolean {
647 return this.isPivotActive() || this.isRowGroupActive() || this.isValueActive();
648 }
649
650 public isAnyFunctionAllowed(): boolean {
651 return this.isAllowPivot() || this.isAllowRowGroup() || this.isAllowValue();
652 }
653
654 public setValueActive(value: boolean, source: ColumnEventType = "api"): void {
655 if (this.aggregationActive !== value) {
656 this.aggregationActive = value;
657 this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_VALUE_CHANGED, source));
658 }
659 }
660
661 public isValueActive(): boolean {
662 return this.aggregationActive;
663 }
664
665 public isAllowPivot(): boolean {
666 return this.colDef.enablePivot === true;
667 }
668
669 public isAllowValue(): boolean {
670 return this.colDef.enableValue === true;
671 }
672
673 public isAllowRowGroup(): boolean {
674 return this.colDef.enableRowGroup === true;
675 }
676
677 public getMenuTabs(defaultValues: string[]): string [] {
678 let menuTabs: string[] = this.getColDef().menuTabs;
679 if (menuTabs == null) {
680 menuTabs = defaultValues;
681 }
682 return menuTabs;
683 }
684}