1 | import {GridOptionsWrapper} from "../gridOptionsWrapper";
|
2 | import {ExpressionService} from "./expressionService";
|
3 | import {ColumnController} from "../columnController/columnController";
|
4 | import {NewValueParams, ValueGetterParams} from "../entities/colDef";
|
5 | import {Autowired, Bean, PostConstruct} from "../context/context";
|
6 | import {RowNode} from "../entities/rowNode";
|
7 | import {Column} from "../entities/column";
|
8 | import {_} from "../utils";
|
9 | import {CellValueChangedEvent, Events} from "../events";
|
10 | import {EventService} from "../eventService";
|
11 | import {ValueCache} from "./valueCache";
|
12 |
|
13 | @Bean('valueService')
|
14 | export class ValueService {
|
15 |
|
16 | @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
|
17 | @Autowired('expressionService') private expressionService: ExpressionService;
|
18 | @Autowired('columnController') private columnController: ColumnController;
|
19 | @Autowired('eventService') private eventService: EventService;
|
20 | @Autowired('valueCache') private valueCache: ValueCache;
|
21 |
|
22 | private cellExpressions: boolean;
|
23 |
|
24 | private initialised = false;
|
25 |
|
26 | @PostConstruct
|
27 | public init(): void {
|
28 | this.cellExpressions = this.gridOptionsWrapper.isEnableCellExpressions();
|
29 | this.initialised = true;
|
30 | }
|
31 |
|
32 | public getValue(column: Column,
|
33 | rowNode: RowNode,
|
34 | forFilter = false,
|
35 | ignoreAggData = false): any {
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | if (!this.initialised) { this.init(); }
|
42 |
|
43 |
|
44 | let colDef = column.getColDef();
|
45 | let field = colDef.field;
|
46 | let colId = column.getId();
|
47 | let data = rowNode.data;
|
48 |
|
49 | let result: any;
|
50 |
|
51 |
|
52 | let groupDataExists = rowNode.groupData && rowNode.groupData[colId] !== undefined;
|
53 | let aggDataExists = !ignoreAggData && rowNode.aggData && rowNode.aggData[colId] !== undefined;
|
54 | if (forFilter && colDef.filterValueGetter) {
|
55 | result = this.executeValueGetter(colDef.filterValueGetter, data, column, rowNode);
|
56 | } else if (groupDataExists) {
|
57 | result = rowNode.groupData[colId];
|
58 | } else if (aggDataExists) {
|
59 | result = rowNode.aggData[colId];
|
60 | } else if (colDef.valueGetter) {
|
61 | result = this.executeValueGetter(colDef.valueGetter, data, column, rowNode);
|
62 | } else if (field && data) {
|
63 | result = _.getValueUsingField(data, field, column.isFieldContainsDots());
|
64 | } else {
|
65 | result = undefined;
|
66 | }
|
67 |
|
68 |
|
69 | if (this.cellExpressions && (typeof result === 'string') && result.indexOf('=') === 0) {
|
70 | let cellValueGetter = result.substring(1);
|
71 | result = this.executeValueGetter(cellValueGetter, data, column, rowNode);
|
72 | }
|
73 |
|
74 | return result;
|
75 | }
|
76 |
|
77 | public setValue(rowNode: RowNode, colKey: string|Column, newValue: any): void {
|
78 | let column = this.columnController.getPrimaryColumn(colKey);
|
79 |
|
80 | if (!rowNode || !column) {
|
81 | return;
|
82 | }
|
83 |
|
84 |
|
85 | let data = rowNode.data;
|
86 | if (_.missing(data)) {
|
87 | rowNode.data = {};
|
88 | }
|
89 |
|
90 |
|
91 | let {field, newValueHandler, valueSetter} = column.getColDef();
|
92 |
|
93 |
|
94 | if (_.missing(field) && _.missing(newValueHandler) && _.missing(valueSetter)) {
|
95 |
|
96 | console.warn(`ag-Grid: you need either field or valueSetter set on colDef for editing to work`);
|
97 | return;
|
98 | }
|
99 |
|
100 | let params: NewValueParams = {
|
101 | node: rowNode,
|
102 | data: rowNode.data,
|
103 | oldValue: this.getValue(column, rowNode),
|
104 | newValue: newValue,
|
105 | colDef: column.getColDef(),
|
106 | column: column,
|
107 | api: this.gridOptionsWrapper.getApi(),
|
108 | columnApi: this.gridOptionsWrapper.getColumnApi(),
|
109 | context: this.gridOptionsWrapper.getContext()
|
110 | };
|
111 |
|
112 | params.newValue = newValue;
|
113 |
|
114 | let valueWasDifferent: boolean;
|
115 | if (_.exists(newValueHandler)) {
|
116 | valueWasDifferent = newValueHandler(params);
|
117 | } else if (_.exists(valueSetter)) {
|
118 | valueWasDifferent = this.expressionService.evaluate(valueSetter, params);
|
119 | } else {
|
120 | valueWasDifferent = this.setValueUsingField(data, field, newValue, column.isFieldContainsDots());
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | if (valueWasDifferent === undefined) {
|
127 | valueWasDifferent = true;
|
128 | }
|
129 |
|
130 |
|
131 |
|
132 |
|
133 | if (!valueWasDifferent) { return; }
|
134 |
|
135 |
|
136 | rowNode.resetQuickFilterAggregateText();
|
137 |
|
138 | this.valueCache.onDataChanged();
|
139 |
|
140 | params.newValue = this.getValue(column, rowNode);
|
141 |
|
142 | if (typeof column.getColDef().onCellValueChanged === 'function') {
|
143 |
|
144 | setTimeout( ()=> column.getColDef().onCellValueChanged(params), 0);
|
145 | }
|
146 |
|
147 | let event: CellValueChangedEvent = {
|
148 | type: Events.EVENT_CELL_VALUE_CHANGED,
|
149 | event: null,
|
150 | rowIndex: rowNode.rowIndex,
|
151 | rowPinned: rowNode.rowPinned,
|
152 | column: params.column,
|
153 | api: params.api,
|
154 | colDef: params.colDef,
|
155 | columnApi: params.columnApi,
|
156 | context: params.context,
|
157 | data: rowNode.data,
|
158 | node: rowNode,
|
159 | oldValue: params.oldValue,
|
160 | newValue: params.newValue,
|
161 | value: params.newValue
|
162 | };
|
163 |
|
164 | this.eventService.dispatchEvent(event);
|
165 | }
|
166 |
|
167 | private setValueUsingField(data: any, field: string, newValue: any, isFieldContainsDots: boolean): boolean {
|
168 |
|
169 | let valuesAreSame: boolean;
|
170 | if (!isFieldContainsDots) {
|
171 | data[field] = newValue;
|
172 | } else {
|
173 |
|
174 | let fieldPieces = field.split('.');
|
175 | let currentObject = data;
|
176 | while (fieldPieces.length > 0 && currentObject) {
|
177 | let fieldPiece = fieldPieces.shift();
|
178 | if (fieldPieces.length === 0) {
|
179 | currentObject[fieldPiece] = newValue;
|
180 | } else {
|
181 | currentObject = currentObject[fieldPiece];
|
182 | }
|
183 | }
|
184 | }
|
185 | return !valuesAreSame;
|
186 | }
|
187 |
|
188 | private executeValueGetter(filterValueGetter: string | Function, data: any, column: Column, rowNode: RowNode): any {
|
189 |
|
190 | let colId = column.getId();
|
191 |
|
192 |
|
193 | let valueFromCache = this.valueCache.getValue(rowNode, colId);
|
194 |
|
195 | if (valueFromCache!==undefined) {
|
196 | return valueFromCache;
|
197 | }
|
198 |
|
199 | let params: ValueGetterParams = {
|
200 | data: data,
|
201 | node: rowNode,
|
202 | column: column,
|
203 | colDef: column.getColDef(),
|
204 | api: this.gridOptionsWrapper.getApi(),
|
205 | columnApi: this.gridOptionsWrapper.getColumnApi(),
|
206 | context: this.gridOptionsWrapper.getContext(),
|
207 | getValue: this.getValueCallback.bind(this, rowNode)
|
208 | };
|
209 |
|
210 | let result = this.expressionService.evaluate(filterValueGetter, params);
|
211 |
|
212 |
|
213 | this.valueCache.setValue(rowNode, colId, result);
|
214 |
|
215 | return result;
|
216 | }
|
217 |
|
218 | private getValueCallback(node: RowNode, field: string): any {
|
219 | let otherColumn = this.columnController.getPrimaryColumn(field);
|
220 | if (otherColumn) {
|
221 | return this.getValue(otherColumn, node);
|
222 | } else {
|
223 | return null;
|
224 | }
|
225 | }
|
226 |
|
227 |
|
228 | public getKeyForNode(col: Column, rowNode: RowNode): any {
|
229 | let value = this.getValue(col, rowNode);
|
230 | let result: any;
|
231 | let keyCreator = col.getColDef().keyCreator;
|
232 |
|
233 | if (keyCreator) {
|
234 | result = keyCreator({value: value});
|
235 | } else {
|
236 | result = value;
|
237 | }
|
238 |
|
239 |
|
240 | if (typeof result === 'string' || result===null || result===undefined) { return result; }
|
241 |
|
242 | result = String(result);
|
243 |
|
244 | if (result==='[object Object]') {
|
245 | _.doOnce( ()=> {
|
246 | console.warn('ag-Grid: a column you are grouping or pivoting by has objects as values. If you want to group by complex objects then either a) use a colDef.keyCreator (se ag-Grid docs) or b) to toString() on the object to return a key');
|
247 | }, 'getKeyForNode - warn about [object,object]');
|
248 | }
|
249 |
|
250 | return result;
|
251 | }
|
252 |
|
253 | }
|