Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit aa78e76

Browse files
authored
fix(backend): incorrect item with GraphQL and useLocalFiltering (#697)
1 parent 98a81bd commit aa78e76

File tree

7 files changed

+166
-7
lines changed

7 files changed

+166
-7
lines changed

src/app/examples/grid-graphql-nopage.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ <h2>{{title}}</h2>
1313
</div>
1414
</div>
1515

16-
<angular-slickgrid gridId="grid25" [columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions"
17-
[dataset]="dataset">
16+
<angular-slickgrid gridId="grid27" [columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions"
17+
[dataset]="dataset">
1818
</angular-slickgrid>
1919
</div>

src/app/modules/angular-slickgrid/components/__tests__/angular-slickgrid-constructor.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ const mockDataView = {
172172
beginUpdate: jest.fn(),
173173
endUpdate: jest.fn(),
174174
getItem: jest.fn(),
175+
getItemCount: jest.fn(),
175176
getItems: jest.fn(),
176177
getLength: jest.fn(),
177178
getItemMetadata: jest.fn(),

src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
772772
startTime: new Date(),
773773
endTime: new Date(),
774774
itemCount: itemCount,
775-
totalItemCount: Array.isArray(this.dataset) ? this.dataset.length : 0
775+
totalItemCount: this.dataView && this.dataView.getItemCount() || 0
776776
};
777777

778778
// when using local (in-memory) dataset, we'll display a warning message when filtered data is empty

src/app/modules/angular-slickgrid/filter-conditions/filterUtilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ export const testFilterCondition = (operator: OperatorString, value1: any, value
7373
return ((value2 && Array.isArray(value2 as string[])) ? (!value2.includes(value1)) : false);
7474
case 'IN_CONTAINS':
7575
if (value2 && Array.isArray(value2) && typeof value1 === 'string') {
76-
return value2.some(item => value1.split(',').includes(item));
76+
return value2.some(item => value1.split(/[\s,]+/).includes(item));
7777
}
7878
return false;
7979
case 'NIN_CONTAINS':
8080
case 'NOT_IN_CONTAINS':
8181
if (value2 && Array.isArray(value2) && typeof value1 === 'string') {
82-
return !value2.some(item => value1.split(',').includes(item));
82+
return !value2.some(item => value1.split(/[\s,]+/).includes(item));
8383
}
8484
return false;
8585
}

src/app/modules/angular-slickgrid/formatters/decimalFormatter.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,3 @@ export const decimalFormatter: Formatter = (row: number, cell: number, value: an
2626
}
2727
return value;
2828
};
29-

src/app/modules/angular-slickgrid/services/filter.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
SlickEventHandler,
2424
} from './../models/index';
2525
import { executeBackendCallback, refreshBackendDataset } from './backend-utilities';
26-
import { deepCopy, getDescendantProperty, mapOperatorByFieldType } from './utilities';
26+
import { deepCopy, getDescendantProperty, mapOperatorByFieldType, sanitizeHtmlToText } from './utilities';
2727
import { FilterConditions, getParsedSearchTermsByFieldType } from './../filter-conditions';
2828
import { FilterFactory } from '../filters/filterFactory';
2929
import { SharedService } from './shared.service';
@@ -472,11 +472,13 @@ export class FilterService {
472472
}
473473

474474
// when using localization (i18n), we should use the formatter output to search as the new cell value
475+
// we will also sanitize/remove HTML tags out of the text (which might be added by multiple-select)
475476
if (columnDef && columnDef.params && columnDef.params.useFormatterOuputToFilter) {
476477
const dataView = grid.getData();
477478
const idPropName = this._gridOptions.datasetIdPropertyName || 'id';
478479
const rowIndex = (dataView && typeof dataView.getIdxById === 'function') ? dataView.getIdxById(item[idPropName]) : 0;
479480
cellValue = (columnDef && typeof columnDef.formatter === 'function') ? columnDef.formatter(rowIndex || 0, columnIndex, cellValue, columnDef, item, this._grid) : '';
481+
cellValue = sanitizeHtmlToText(cellValue); // also remove any html tag
480482
}
481483

482484
// make sure cell value is always a string
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/// <reference types="cypress" />
2+
3+
describe('Example 27 - GraphQL Basic API without Pagination', () => {
4+
const GRID_ROW_HEIGHT = 35;
5+
const fullPreTitles = ['Country', 'Language', 'Continent'];
6+
const fullTitles = ['Code', 'Name', 'Native', 'Phone Area Code', 'Currency', 'Emoji', 'Names', 'Native', 'Codes', 'Name', 'Code'];
7+
8+
it('should display Example title', () => {
9+
cy.visit(`${Cypress.config('baseExampleUrl')}/graphql-nopage`);
10+
cy.get('h2').should('contain', 'Example 27: GraphQL Basic API without Pagination');
11+
});
12+
13+
it('should display a processing alert which will change to done', () => {
14+
cy.get('[data-test=status]').should('contain', 'processing');
15+
cy.get('[data-test=status]').should('contain', 'done');
16+
});
17+
18+
it('should have exact Column Pre-Header & Column Header Titles in the grid', () => {
19+
cy.get('#grid27')
20+
.find('.slick-header-columns:nth(0)')
21+
.children()
22+
.each(($child, index) => expect($child.text()).to.eq(fullPreTitles[index]));
23+
24+
cy.get('#grid27')
25+
.find('.slick-header-columns:nth(1)')
26+
.children()
27+
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
28+
});
29+
30+
it('should expect first 3 rows to be an exact match of data provided by the external GraphQL API', () => {
31+
cy.get('.right-footer.metrics')
32+
.contains('250 of 250 items');
33+
34+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(0)`).should('contain', 'AD');
35+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(1)`).should('contain', 'Andorra');
36+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Andorra');
37+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(3)`).should('contain', '376');
38+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(4)`).should('contain', 'EUR');
39+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(6)`).should('contain', 'Catalan');
40+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(7)`).should('contain', 'Català');
41+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'ca');
42+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('contain', 'Europe');
43+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(10)`).should('contain', 'EU');
44+
45+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(0)`).should('contain', 'AE');
46+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(1)`).should('contain', 'United Arab Emirates');
47+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(2)`).should('contain', 'دولة الإمارات العربية المتحدة');
48+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(3)`).should('contain', '971');
49+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(4)`).should('contain', 'AED');
50+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(6)`).should('contain', 'Arabic');
51+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(7)`).should('contain', 'العربية');
52+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(8)`).should('contain', 'ar');
53+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(9)`).should('contain', 'Asia');
54+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(10)`).should('contain', 'AS');
55+
56+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(0)`).should('contain', 'AF');
57+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(1)`).should('contain', 'Afghanistan');
58+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(2)`).should('contain', 'افغانستان');
59+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(3)`).should('contain', '93');
60+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(4)`).should('contain', 'AFN');
61+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(6)`).should('contain', 'Pashto, Uzbek, Turkmen');
62+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(7)`).should('contain', 'پښتو, Ўзбек, Туркмен / تركمن');
63+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(8)`).should('contain', 'ps, uz, tk');
64+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(9)`).should('contain', 'Asia');
65+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 2}px"] > .slick-cell:nth(10)`).should('contain', 'AS');
66+
});
67+
68+
it('should sort by country name and expect first 2 rows as Afghanistan and Albania', () => {
69+
cy.get(`.slick-header-columns:nth(1) .slick-header-column:nth-child(2)`).contains('Name').click();
70+
71+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(0)`).should('contain', 'AF');
72+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(1)`).should('contain', 'Afghanistan');
73+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'افغانستان');
74+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(3)`).should('contain', '93');
75+
76+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(0)`).should('contain', 'AL');
77+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(1)`).should('contain', 'Albania');
78+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(2)`).should('contain', 'Shqipëria');
79+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(3)`).should('contain', '355');
80+
});
81+
82+
it('should filter by Language Codes "fr, de" and expect 2 rows of data in the grid', () => {
83+
cy.get('.search-filter.filter-languageCode')
84+
.type('fr, de');
85+
86+
cy.get('.right-footer.metrics')
87+
.contains('2 of 250 items');
88+
89+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(0)`).should('contain', 'BE');
90+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(1)`).should('contain', 'Belgium');
91+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'België');
92+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(3)`).should('contain', '32');
93+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(4)`).should('contain', 'EUR');
94+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(6)`).should('contain', 'Dutch, French, German');
95+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(7)`).should('contain', 'Nederlands, Français, Deutsch');
96+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'nl, fr, de');
97+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('contain', 'Europe');
98+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(10)`).should('contain', 'EU');
99+
100+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(0)`).should('contain', 'LU');
101+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(1)`).should('contain', 'Luxembourg');
102+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(2)`).should('contain', 'Luxembourg');
103+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(3)`).should('contain', '352');
104+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(4)`).should('contain', 'EUR');
105+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(6)`).should('contain', 'French, German, Luxembourgish');
106+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(7)`).should('contain', 'Français, Deutsch, Lëtzebuergesch');
107+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(8)`).should('contain', 'fr, de, lb');
108+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(9)`).should('contain', 'Europe');
109+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(10)`).should('contain', 'EU');
110+
});
111+
112+
it('should Clear all Filters and expect all rows to be back', () => {
113+
cy.get('#grid27')
114+
.find('button.slick-gridmenu-button')
115+
.trigger('click')
116+
.click();
117+
118+
cy.get(`.slick-gridmenu:visible`)
119+
.find('.slick-gridmenu-item')
120+
.first()
121+
.find('span')
122+
.contains('Clear all Filters')
123+
.click();
124+
125+
cy.get('.right-footer.metrics')
126+
.contains('250 of 250 items');
127+
});
128+
129+
it('should filter Language Native with "Aymar" and expect only 1 row in the grid', () => {
130+
cy.get('div.ms-filter.filter-languageNative')
131+
.trigger('click');
132+
133+
cy.get('.ms-search:visible')
134+
.type('Aymar');
135+
136+
cy.get('.ms-drop:visible')
137+
.contains('Aymar')
138+
.click();
139+
140+
cy.get('.ms-ok-button:visible')
141+
.click();
142+
143+
cy.get('.right-footer.metrics')
144+
.contains('1 of 250 items');
145+
146+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(0)`).should('contain', 'BO');
147+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(1)`).should('contain', 'Bolivia');
148+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Bolivia');
149+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(3)`).should('contain', '591');
150+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(4)`).should('contain', 'BOB,BOV');
151+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(6)`).should('contain', 'Spanish, Aymara, Quechua');
152+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(7)`).should('contain', 'Español, Aymar, Runa Simi');
153+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'es, ay, qu');
154+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('contain', 'South America');
155+
cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(10)`).should('contain', 'SA');
156+
});
157+
});

0 commit comments

Comments
 (0)