(sgOnCellChange)="onCellChanged($event.detail.eventData, $event.detail.args)"
(sgOnClick)="onCellClicked($event.detail.eventData, $event.detail.args)"
(sgOnValidationError)="onCellValidation($event.detail.eventData, $event.detail.args)"
+ (sgOnActiveCellChanged)="onActiveCellChanged($event.detail.eventData, $event.detail.args)"
[columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions" [dataset]="dataset">
diff --git a/src/app/examples/grid-angular.component.ts b/src/app/examples/grid-angular.component.ts
index 48dc7f383..d0e632c0e 100644
--- a/src/app/examples/grid-angular.component.ts
+++ b/src/app/examples/grid-angular.component.ts
@@ -7,11 +7,13 @@ import {
Editors,
FieldType,
Filters,
+ Formatter,
Formatters,
GridOption,
OnEventArgs,
} from './../modules/angular-slickgrid';
import { EditorNgSelectComponent } from './editor-ng-select.component';
+import { CustomActionFormatterComponent } from './custom-actionFormatter.component';
import { CustomAngularComponentEditor } from './custom-angularComponentEditor';
import { CustomAngularComponentFilter } from './custom-angularComponentFilter';
import { CustomTitleFormatterComponent } from './custom-titleFormatter.component';
@@ -23,6 +25,17 @@ declare var $: any;
const NB_ITEMS = 100;
+const customActionFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any, grid: any) => {
+ // use the same button text "Action" as the "CustomActionFormatterComponent" button text
+ // we basically recreate a dropdown on top of this one here which is just an empty one to show something in the grid
+ return `
+
+
`;
+};
+
@Component({
templateUrl: './grid-angular.component.html',
styleUrls: ['./grid-angular.component.scss'],
@@ -218,7 +231,8 @@ export class GridAngularComponent implements OnInit {
editor: {
model: Editors.date
},
- }
+ },
+ { id: 'action', name: 'Action', field: 'id', formatter: customActionFormatter, width: 70 }
];
this.gridOptions = {
@@ -329,8 +343,46 @@ export class GridAngularComponent implements OnInit {
const componentOutput = this.angularUtilService.createAngularComponent(colDef.params.component);
Object.assign(componentOutput.componentRef.instance, { item: dataContext });
- // use a delay to make sure Angular ran at least a full cycle and it finished rendering the Component
+ // use a delay to make sure Angular ran at least a full cycle and make sure it finished rendering the Component
setTimeout(() => $(cellNode).empty().html(componentOutput.domElement));
}
}
+
+ /* Create an Action Dropdown Menu */
+ deleteCell(rowNumber: number) {
+ const item = this.angularGrid.dataView.getItem(rowNumber);
+ this.angularGrid.gridService.deleteItemById(item.id);
+ }
+
+ onActiveCellChanged(event, args) {
+ if (args.cell !== 6) {
+ return; // don't do anything unless it's the Action column which is at position 6 in this grid
+ }
+
+ $('#myDrop').remove(); // make sure to remove previous Action dropdown, you don't want to have 100 after a 100 clicks...
+ const cell = args.cell;
+ const row = args.row;
+
+ // hide the dropdown we created as a Formatter, we'll redisplay it later
+ const cellPos = $(`#myDrop-r${row}-c${cell}`).offset();
+
+ const componentOutput = this.angularUtilService.createAngularComponent(CustomActionFormatterComponent);
+
+ // pass "this" and the row number to the Component instance (CustomActionFormatter) so that we can call "parent.deleteCell(row)" with (click)
+ Object.assign(componentOutput.componentRef.instance, { parent: this, row: args.row });
+
+ // use a delay to make sure Angular ran at least a full cycle and make sure it finished rendering the Component before using it
+ setTimeout(() => {
+ const elm = $(componentOutput.domElement);
+ elm.appendTo('body');
+ elm.css('position', 'absolute');
+ elm.css('top', cellPos.top + 5);
+ elm.css('left', cellPos.left);
+ $('#myDrop').addClass('open');
+
+ $('#myDrop').on('hidden.bs.dropdown', () => {
+ $(`#myDrop-r${row}-c${cell}`).show();
+ });
+ });
+ }
}
diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
index aaf6e67dd..e1ec31006 100644
--- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
+++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
@@ -398,10 +398,17 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
if (backendApi) {
// internalPostProcess only works (for now) with a GraphQL Service, so make sure it is that type
if (backendApi && backendApi.service instanceof GraphqlService) {
- backendApi.internalPostProcess = (processResult: any) => {
+ backendApi.internalPostProcess = (processResult: GraphqlResult) => {
const datasetName = (backendApi && backendApi.service && typeof backendApi.service.getDatasetName === 'function') ? backendApi.service.getDatasetName() : '';
if (processResult && processResult.data && processResult.data[datasetName]) {
this._dataset = processResult.data[datasetName].nodes;
+ if (processResult.data[datasetName].listSeparator) {
+ // if the "listSeparator" is available in the GraphQL result, we'll override the ExportOptions Delimiter with this new info
+ if (!this.gridOptions.exportOptions) {
+ this.gridOptions.exportOptions = {};
+ }
+ this.gridOptions.exportOptions.delimiterOverride = processResult.data[datasetName].listSeparator.toString();
+ }
this.refreshGridData(this._dataset, processResult.data[datasetName].totalCount);
} else {
this._dataset = [];
diff --git a/src/app/modules/angular-slickgrid/models/exportOption.interface.ts b/src/app/modules/angular-slickgrid/models/exportOption.interface.ts
index af9ce6c74..f70733801 100644
--- a/src/app/modules/angular-slickgrid/models/exportOption.interface.ts
+++ b/src/app/modules/angular-slickgrid/models/exportOption.interface.ts
@@ -4,6 +4,9 @@ export interface ExportOption {
/** export delimiter, can be (comma, tab, ... or even custom string). */
delimiter?: DelimiterType | string;
+ /** Allows you to override for the export delimiter, useful when adding the "listSeparator" to the GraphQL query */
+ delimiterOverride?: DelimiterType | string;
+
/** Defaults to false, which leads to all Formatters of the grid being evaluated on export. You can also override a column by changing the propery on the column itself */
exportWithFormatter?: boolean;
diff --git a/src/app/modules/angular-slickgrid/models/graphqlResult.interface.ts b/src/app/modules/angular-slickgrid/models/graphqlResult.interface.ts
index 298494a70..1e1e601f5 100644
--- a/src/app/modules/angular-slickgrid/models/graphqlResult.interface.ts
+++ b/src/app/modules/angular-slickgrid/models/graphqlResult.interface.ts
@@ -1,14 +1,16 @@
+import { DelimiterType } from './delimiterType.enum';
import { Metrics } from './metrics.interface';
import { Statistic } from './statistic.interface';
export interface GraphqlResult {
data: {
[datasetName: string]: {
- nodes: any[],
+ nodes: any[];
pageInfo: {
hasNextPage: boolean;
- },
- totalCount: number
+ };
+ listSeparator?: DelimiterType;
+ totalCount: number;
}
};
diff --git a/src/app/modules/angular-slickgrid/models/graphqlServiceOption.interface.ts b/src/app/modules/angular-slickgrid/models/graphqlServiceOption.interface.ts
index 1cd0efc79..496670201 100644
--- a/src/app/modules/angular-slickgrid/models/graphqlServiceOption.interface.ts
+++ b/src/app/modules/angular-slickgrid/models/graphqlServiceOption.interface.ts
@@ -7,11 +7,17 @@ import { GraphqlPaginationOption } from './graphqlPaginationOption.interface';
export interface GraphqlServiceOption extends BackendServiceOption {
/**
- * When using Translation, we probably want to add locale in the query for the filterBy/orderBy to work
- * ex.: users(first: 10, offset: 0, locale: "en-CA", filterBy: [{field: name, operator: EQ, value:"John"}]) {
+ * When using Translation, we probably want to add locale as a query parameter for the filterBy/orderBy to work
+ * ex.: users(first: 10, offset: 0, locale: "en-CA", filterBy: [{field: name, operator: EQ, value:"John"}]) { }
*/
addLocaleIntoQuery?: boolean;
+ /**
+ * Add the Current User List Separator to the result query (in English the separator is comma ",").
+ * This is useful to set the "delimiter" property when using Export CSV, for example French uses semicolon ";" as a delimiter/separator
+ */
+ addListSeparator?: boolean;
+
/** What is the dataset, this is required for the GraphQL query to be built */
datasetName?: string;
diff --git a/src/app/modules/angular-slickgrid/services/__tests__/export.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/export.service.spec.ts
index af7ded41c..d63413eb3 100644
--- a/src/app/modules/angular-slickgrid/services/__tests__/export.service.spec.ts
+++ b/src/app/modules/angular-slickgrid/services/__tests__/export.service.spec.ts
@@ -250,6 +250,10 @@ describe('ExportService', () => {
describe('startDownloadFile call after all private methods ran ', () => {
let mockCollection: any[];
+ beforeEach(() => {
+ mockGridOptions.exportOptions = { delimiterOverride: '' };
+ });
+
it(`should have the Order exported correctly with multiple formatters which have 1 of them returning an object with a text property (instead of simple string)`, (done) => {
mockCollection = [{ id: 0, userId: '1E06', firstName: 'John', lastName: 'Z', position: 'SALES_REP', order: 10 }];
jest.spyOn(dataViewStub, 'getLength').mockReturnValue(mockCollection.length);
@@ -274,6 +278,31 @@ describe('ExportService', () => {
});
});
+ it(`should have the Order exported correctly with multiple formatters and use a different delimiter when "delimiterOverride" is provided`, (done) => {
+ mockGridOptions.exportOptions = { delimiterOverride: DelimiterType.doubleSemicolon };
+ mockCollection = [{ id: 0, userId: '1E06', firstName: 'John', lastName: 'Z', position: 'SALES_REP', order: 10 }];
+ jest.spyOn(dataViewStub, 'getLength').mockReturnValue(mockCollection.length);
+ jest.spyOn(dataViewStub, 'getItem').mockReturnValue(null).mockReturnValueOnce(mockCollection[0]);
+ const spyOnAfter = jest.spyOn(service.onGridAfterExportToFile, 'next');
+ const spyUrlCreate = jest.spyOn(URL, 'createObjectURL');
+ const spyDownload = jest.spyOn(service, 'startDownloadFile');
+
+ const optionExpectation = { filename: 'export.csv', format: 'csv', useUtf8WithBom: false };
+ const contentExpectation =
+ `"User Id";;"FirstName";;"LastName";;"Position";;"Order"
+ ="1E06";;"John";;"Z";;"SALES_REP";;"10"`;
+
+ service.init(gridStub, dataViewStub);
+ service.exportToFile(mockExportCsvOptions);
+
+ setTimeout(() => {
+ expect(spyOnAfter).toHaveBeenCalledWith(optionExpectation);
+ expect(spyUrlCreate).toHaveBeenCalledWith(mockCsvBlob);
+ expect(spyDownload).toHaveBeenCalledWith({ ...optionExpectation, content: removeMultipleSpaces(contentExpectation) });
+ done();
+ });
+ });
+
it(`should have the UserId escape with equal sign showing as prefix, to avoid Excel casting the value 1E06 to 1 exponential 6,
when "exportCsvForceToKeepAsString" is enable in its column definition`, (done) => {
mockCollection = [{ id: 0, userId: '1E06', firstName: 'John', lastName: 'Z', position: 'SALES_REP', order: 10 }];
diff --git a/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts
index cf8b36677..485db6b7a 100644
--- a/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts
+++ b/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts
@@ -243,6 +243,16 @@ describe('GraphqlService', () => {
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
});
+ it('should include "listSeparator" in the query string when option "addListSeparator" is enabled', () => {
+ const expectation = `query{ users(first:10, offset:0){ listSeparator, totalCount, nodes{ id, field1, field2 }}}`;
+ const columns = [{ id: 'field1', field: 'field1', width: 100 }, { id: 'field2', field: 'field2', width: 100 }];
+
+ service.init({ datasetName: 'users', columnDefinitions: columns, addListSeparator: true }, paginationOptions, gridStub);
+ const query = service.buildQuery();
+
+ expect(removeSpaces(query)).toBe(removeSpaces(expectation));
+ });
+
it('should include default locale "en" in the query string when option "addLocaleIntoQuery" is enabled and i18n is not defined', () => {
const expectation = `query{ users(first:10, offset:0, locale: "en"){ totalCount, nodes{ id, field1, field2 }}}`;
const columns = [{ id: 'field1', field: 'field1', width: 100 }, { id: 'field2', field: 'field2', width: 100 }];
@@ -415,6 +425,7 @@ describe('GraphqlService', () => {
});
it('should return a query with the new filter', () => {
+ serviceOptions.addListSeparator = false;
const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}]) { totalCount,nodes{ id,field1,field2 } }}`;
const querySpy = jest.spyOn(service, 'buildQuery');
const resetSpy = jest.spyOn(service, 'resetPaginationOptions');
@@ -441,9 +452,10 @@ describe('GraphqlService', () => {
});
it('should return a query with a new filter when previous filters exists', () => {
+ serviceOptions.addListSeparator = true;
const expectation = `query{users(first:10, offset:0,
filterBy:[{field:gender, operator:EQ, value:"female"}, {field:firstName, operator:StartsWith, value:"John"}])
- { totalCount,nodes{ id,field1,field2 } }}`;
+ { listSeparator, totalCount,nodes{ id,field1,field2 } }}`;
const querySpy = jest.spyOn(service, 'buildQuery');
const resetSpy = jest.spyOn(service, 'resetPaginationOptions');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
@@ -476,6 +488,7 @@ describe('GraphqlService', () => {
describe('processOnPaginationChanged method', () => {
it('should return a query with the new pagination', () => {
+ serviceOptions.addListSeparator = false;
const expectation = `query{users(first:20, offset:40) { totalCount,nodes { id, field1, field2 }}}`;
const querySpy = jest.spyOn(service, 'buildQuery');
@@ -489,7 +502,8 @@ describe('GraphqlService', () => {
});
it('should return a query with the new pagination and use pagination size options that was passed to service options when it is not provided as argument to "processOnPaginationChanged"', () => {
- const expectation = `query{users(first:10, offset:20) { totalCount,nodes { id, field1, field2 }}}`;
+ serviceOptions.addListSeparator = true;
+ const expectation = `query{users(first:10, offset:20) { listSeparator, totalCount,nodes { id, field1, field2 }}}`;
const querySpy = jest.spyOn(service, 'buildQuery');
service.init(serviceOptions, paginationOptions, gridStub);
@@ -519,6 +533,7 @@ describe('GraphqlService', () => {
describe('processOnSortChanged method', () => {
it('should return a query with the new sorting when using single sort', () => {
+ serviceOptions.addListSeparator = false;
const expectation = `query{ users(first:10, offset:0, orderBy:[{field:gender, direction: DESC}]) { totalCount,nodes{ id,field1,field2 } }}`;
const querySpy = jest.spyOn(service, 'buildQuery');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
@@ -532,9 +547,10 @@ describe('GraphqlService', () => {
});
it('should return a query with the multiple new sorting when using multiColumnSort', () => {
+ serviceOptions.addListSeparator = true;
const expectation = `query{ users(first:10, offset:0,
orderBy:[{field:gender, direction: DESC}, {field:firstName, direction: ASC}]) {
- totalCount,nodes{ id,field1,field2 } }}`;
+ listSeparator, totalCount,nodes{ id,field1,field2 } }}`;
const querySpy = jest.spyOn(service, 'buildQuery');
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnName = { id: 'firstName', field: 'firstName' } as Column;
@@ -553,6 +569,7 @@ describe('GraphqlService', () => {
describe('updateFilters method', () => {
beforeEach(() => {
serviceOptions.columnDefinitions = [{ id: 'company', field: 'company' }, { id: 'gender', field: 'gender' }, { id: 'name', field: 'name' }];
+ serviceOptions.addListSeparator = false;
});
it('should throw an error when filter columnId is not found to be part of the column definitions', () => {
@@ -569,7 +586,9 @@ describe('GraphqlService', () => {
});
it('should return a query with the new filter when filters are passed as a filter trigger by a filter event and is of type ColumnFilters', () => {
- const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}]) { totalCount,nodes{ id,company,gender,name } }}`;
+ serviceOptions.addListSeparator = true;
+ const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}]) {
+ listSeparator, totalCount,nodes{ id,company,gender,name } }}`;
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnFilters = {
gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' },
@@ -913,7 +932,8 @@ describe('GraphqlService', () => {
});
it('should return a query without any sorting after clearFilters was called', () => {
- const expectation = `query{ users(first:10,offset:0) { totalCount,nodes{id, company, gender,name} }}`;
+ serviceOptions.addListSeparator = true;
+ const expectation = `query{ users(first:10,offset:0) { listSeparator, totalCount, nodes {id, company, gender,name} }}`;
const mockColumn = { id: 'gender', field: 'gender' } as Column;
const mockColumnFilters = {
gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' },
@@ -933,10 +953,13 @@ describe('GraphqlService', () => {
describe('presets', () => {
beforeEach(() => {
serviceOptions.columnDefinitions = [{ id: 'company', field: 'company' }, { id: 'gender', field: 'gender' }, { id: 'duration', field: 'duration' }, { id: 'startDate', field: 'startDate' }];
+ serviceOptions.addListSeparator = false;
});
it('should return a query with search having a range of exclusive numbers when the search value contains 2 (..) to represent a range of numbers', () => {
- const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GT, value:"2"}, {field:duration, operator:LT, value:"33"}]) { totalCount,nodes{ id,company,gender,duration,startDate } }}`;
+ serviceOptions.addListSeparator = true;
+ const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GT, value:"2"}, {field:duration, operator:LT, value:"33"}]) {
+ listSeparator, totalCount,nodes{ id,company,gender,duration,startDate } }}`;
const presetFilters = [
{ columnId: 'duration', searchTerms: ['2..33'] },
] as CurrentFilter[];
@@ -1044,12 +1067,14 @@ describe('GraphqlService', () => {
describe('updateSorters method', () => {
beforeEach(() => {
serviceOptions.columnDefinitions = [{ id: 'company', field: 'company' }, { id: 'gender', field: 'gender' }, { id: 'name', field: 'name' }];
+ serviceOptions.addListSeparator = false;
});
it('should return a query with the multiple new sorting when using multiColumnSort', () => {
+ serviceOptions.addListSeparator = true;
const expectation = `query{ users(first:10, offset:0,
orderBy:[{field:gender, direction: DESC}, {field:firstName, direction: ASC}]) {
- totalCount,nodes{ id, company, gender, name } }}`;
+ listSeparator, totalCount,nodes{ id, company, gender, name } }}`;
const mockColumnSort = [
{ columnId: 'gender', sortCol: { id: 'gender', field: 'gender' }, sortAsc: false },
{ columnId: 'firstName', sortCol: { id: 'firstName', field: 'firstName' }, sortAsc: true }
@@ -1136,8 +1161,9 @@ describe('GraphqlService', () => {
});
it('should return a query without any sorting after clearSorters was called', () => {
+ serviceOptions.addListSeparator = true;
const expectation = `query { users(first:10, offset:0) {
- totalCount, nodes { id,company,gender,name }}}`;
+ listSeparator, totalCount, nodes { id,company,gender,name }}}`;
const mockColumnSort = [
{ columnId: 'gender', sortCol: { id: 'gender', field: 'gender' }, sortAsc: false },
{ columnId: 'firstName', sortCol: { id: 'firstName', field: 'firstName' }, sortAsc: true }
diff --git a/src/app/modules/angular-slickgrid/services/export.service.ts b/src/app/modules/angular-slickgrid/services/export.service.ts
index adebcac5e..4733f5213 100644
--- a/src/app/modules/angular-slickgrid/services/export.service.ts
+++ b/src/app/modules/angular-slickgrid/services/export.service.ts
@@ -1,5 +1,8 @@
import { Injectable, Optional } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
+import { TextEncoder } from 'text-encoding-utf-8';
+import { Subject } from 'rxjs';
+
import {
Column,
ExportOption,
@@ -10,8 +13,6 @@ import {
} from './../models/index';
import { Constants } from './../constants';
import { addWhiteSpaces, htmlEntityDecode, sanitizeHtmlToText, titleCase } from './../services/utilities';
-import { TextEncoder } from 'text-encoding-utf-8';
-import { Subject } from 'rxjs';
// using external non-typed js libraries
declare let $: any;
@@ -23,6 +24,8 @@ export interface ExportColumnHeader {
@Injectable()
export class ExportService {
+ private _delimiter = ',';
+ private _fileFormat = FileType.csv;
private _lineCarriageReturn = '\n';
private _dataView: any;
private _grid: any;
@@ -77,6 +80,8 @@ export class ExportService {
return new Promise((resolve, reject) => {
this.onGridBeforeExportToFile.next(true);
this._exportOptions = $.extend(true, {}, this._gridOptions.exportOptions, options);
+ this._delimiter = this._exportOptions.delimiterOverride || this._exportOptions.delimiter || '';
+ this._fileFormat = this._exportOptions.format || FileType.csv;
// get the CSV output from the grid data
const dataOutput = this.getDataOutput();
@@ -86,8 +91,8 @@ export class ExportService {
setTimeout(() => {
try {
const downloadOptions = {
- filename: `${this._exportOptions.filename}.${this._exportOptions.format}`,
- format: this._exportOptions.format,
+ filename: `${this._exportOptions.filename}.${this._fileFormat}`,
+ format: this._fileFormat,
useUtf8WithBom: this._exportOptions.hasOwnProperty('useUtf8WithBom') ? this._exportOptions.useUtf8WithBom : true
};
@@ -165,8 +170,6 @@ export class ExportService {
private getDataOutput(): string {
const columns = this._grid.getColumns() || [];
- const delimiter = this._exportOptions.delimiter || '';
- const format = this._exportOptions.format || '';
// Group By text, it could be set in the export options or from translation or if nothing is found then use the English constant text
let groupByColumnHeader = this._exportOptions.groupingColumnHeaderTitle;
@@ -177,7 +180,7 @@ export class ExportService {
}
// a CSV needs double quotes wrapper, the other types do not need any wrapper
- this._exportQuoteWrapper = (format === FileType.csv) ? '"' : '';
+ this._exportQuoteWrapper = (this._fileFormat === FileType.csv) ? '"' : '';
// data variable which will hold all the fields data of a row
let outputDataString = '';
@@ -187,7 +190,7 @@ export class ExportService {
const grouping = this._dataView.getGrouping();
if (grouping && Array.isArray(grouping) && grouping.length > 0) {
this._hasGroupedItems = true;
- outputDataString += (format === FileType.csv) ? `"${groupByColumnHeader}"${delimiter}` : `${groupByColumnHeader}${delimiter}`;
+ outputDataString += (this._fileFormat === FileType.csv) ? `"${groupByColumnHeader}"${this._delimiter}` : `${groupByColumnHeader}${this._delimiter}`;
} else {
this._hasGroupedItems = false;
}
@@ -199,7 +202,7 @@ export class ExportService {
const outputHeaderTitles = this._columnHeaders.map((header) => {
return this._exportQuoteWrapper + header.title + this._exportQuoteWrapper;
});
- outputDataString += (outputHeaderTitles.join(delimiter) + this._lineCarriageReturn);
+ outputDataString += (outputHeaderTitles.join(this._delimiter) + this._lineCarriageReturn);
}
// Populate the rest of the Grid Data
@@ -276,8 +279,6 @@ export class ExportService {
private readRegularRowData(columns: Column[], row: number, itemObj: any) {
let idx = 0;
const rowOutputStrings = [];
- const delimiter = this._exportOptions.delimiter;
- const format = this._exportOptions.format;
const exportQuoteWrapper = this._exportQuoteWrapper;
for (let col = 0, ln = columns.length; col < ln; col++) {
@@ -291,7 +292,7 @@ export class ExportService {
// if we are grouping and are on 1st column index, we need to skip this column since it will be used later by the grouping text:: Group by [columnX]
if (this._hasGroupedItems && idx === 0) {
- const emptyValue = format === FileType.csv ? `""` : '';
+ const emptyValue = this._fileFormat === FileType.csv ? `""` : '';
rowOutputStrings.push(emptyValue);
}
@@ -341,7 +342,7 @@ export class ExportService {
}
// when CSV we also need to escape double quotes twice, so " becomes ""
- if (format === FileType.csv && itemData) {
+ if (this._fileFormat === FileType.csv && itemData) {
itemData = itemData.toString().replace(/"/gi, `""`);
}
@@ -353,7 +354,7 @@ export class ExportService {
idx++;
}
- return rowOutputStrings.join(delimiter);
+ return rowOutputStrings.join(this._delimiter);
}
/**
@@ -363,11 +364,10 @@ export class ExportService {
private readGroupedTitleRow(itemObj: any) {
let groupName = sanitizeHtmlToText(itemObj.title);
const exportQuoteWrapper = this._exportQuoteWrapper;
- const format = this._exportOptions.format;
groupName = addWhiteSpaces(5 * itemObj.level) + groupName;
- if (format === FileType.csv) {
+ if (this._fileFormat === FileType.csv) {
// when CSV we also need to escape double quotes twice, so " becomes ""
groupName = groupName.toString().replace(/"/gi, `""`);
}
diff --git a/src/app/modules/angular-slickgrid/services/graphql.service.ts b/src/app/modules/angular-slickgrid/services/graphql.service.ts
index 9693d1246..29319c25d 100644
--- a/src/app/modules/angular-slickgrid/services/graphql.service.ts
+++ b/src/app/modules/angular-slickgrid/services/graphql.service.ts
@@ -101,19 +101,28 @@ export class GraphqlService implements BackendService {
}
const filters = this.buildFilterQuery(columnIds);
+ let graphqlFields = [];
if (this.options.isWithCursor) {
// ...pageInfo { hasNextPage, endCursor }, edges { cursor, node { _filters_ } }
const pageInfoQb = new QueryBuilder('pageInfo');
pageInfoQb.find('hasNextPage', 'endCursor');
dataQb.find(['cursor', { node: filters }]);
- datasetQb.find(['totalCount', pageInfoQb, dataQb]);
+ graphqlFields = ['totalCount', pageInfoQb, dataQb];
} else {
// ...nodes { _filters_ }
dataQb.find(filters);
- datasetQb.find(['totalCount', dataQb]);
+ graphqlFields = ['totalCount', dataQb];
}
+ // are we adding the current user listSeparator to the fields query result?
+ if (this.options.addListSeparator) {
+ graphqlFields.unshift('listSeparator');
+ }
+
+ // properties to be returned by the query
+ datasetQb.find(graphqlFields);
+
// add dataset filters, could be Pagination and SortingFilters and/or FieldFilters
let datasetFilters: GraphqlDatasetFilter = {};