From 1a9d8fbadea7f3d6abb0b0331cecb7dd12ad068f Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 29 Apr 2026 14:57:43 +0200 Subject: [PATCH] test: attempting to reproduce --- src/dev-app/table/MockedDataType.ts | 8 + .../table/PagedTableDataSourceConfig.ts | 13 + .../table/PagedTableDataSourceNextPageData.ts | 4 + src/dev-app/table/TableDataSourceConfig.ts | 3 + src/dev-app/table/TableExampleColumn.ts | 10 + src/dev-app/table/data.ts | 804 ++++++++++++++++++ src/dev-app/table/paged-data-source.ts | 89 ++ src/dev-app/table/table-data-source.ts | 34 + src/dev-app/table/table-demo.html | 155 ++-- src/dev-app/table/table-demo.ts | 163 ++-- 10 files changed, 1117 insertions(+), 166 deletions(-) create mode 100644 src/dev-app/table/MockedDataType.ts create mode 100644 src/dev-app/table/PagedTableDataSourceConfig.ts create mode 100644 src/dev-app/table/PagedTableDataSourceNextPageData.ts create mode 100644 src/dev-app/table/TableDataSourceConfig.ts create mode 100644 src/dev-app/table/TableExampleColumn.ts create mode 100644 src/dev-app/table/data.ts create mode 100644 src/dev-app/table/paged-data-source.ts create mode 100644 src/dev-app/table/table-data-source.ts diff --git a/src/dev-app/table/MockedDataType.ts b/src/dev-app/table/MockedDataType.ts new file mode 100644 index 000000000000..215b9fedb3cd --- /dev/null +++ b/src/dev-app/table/MockedDataType.ts @@ -0,0 +1,8 @@ +export interface MockedDataType { + id: number; + first_name: string; + last_name: string; + email: string; + gender: string; + ip_address: string; +} diff --git a/src/dev-app/table/PagedTableDataSourceConfig.ts b/src/dev-app/table/PagedTableDataSourceConfig.ts new file mode 100644 index 000000000000..875c9431d718 --- /dev/null +++ b/src/dev-app/table/PagedTableDataSourceConfig.ts @@ -0,0 +1,13 @@ +import {Observable} from 'rxjs'; +import {PagedTableDataSourceNextPageData} from './PagedTableDataSourceNextPageData'; +import {TableDataSourceConfig} from './TableDataSourceConfig'; + +export interface PagedTableDataSourceConfig extends TableDataSourceConfig { + pageSize?: number; + itemsUntilReq?: number; + nextPageHandler: ( + pageSize: number, + nextPageNumber: number, + nextPageToken?: string, + ) => Observable>; +} diff --git a/src/dev-app/table/PagedTableDataSourceNextPageData.ts b/src/dev-app/table/PagedTableDataSourceNextPageData.ts new file mode 100644 index 000000000000..5ec08a12ab5e --- /dev/null +++ b/src/dev-app/table/PagedTableDataSourceNextPageData.ts @@ -0,0 +1,4 @@ +export interface PagedTableDataSourceNextPageData { + content: T[]; + nextPageToken?: string; +} diff --git a/src/dev-app/table/TableDataSourceConfig.ts b/src/dev-app/table/TableDataSourceConfig.ts new file mode 100644 index 000000000000..0da289463aac --- /dev/null +++ b/src/dev-app/table/TableDataSourceConfig.ts @@ -0,0 +1,3 @@ +export interface TableDataSourceConfig { + itemSize?: number; +} diff --git a/src/dev-app/table/TableExampleColumn.ts b/src/dev-app/table/TableExampleColumn.ts new file mode 100644 index 000000000000..96e618965c0c --- /dev/null +++ b/src/dev-app/table/TableExampleColumn.ts @@ -0,0 +1,10 @@ +export enum TableColumn { + ID = 'id', + FIRST_NAME = 'first_name', + LAST_NAME = 'last_name', + EMAIL = 'email', + GENDER = 'gender', + IP_ADDRESS = 'ip_address', + ACTIONS = 'actions', + MOBILE_VIEW = 'mobile_view', +} diff --git a/src/dev-app/table/data.ts b/src/dev-app/table/data.ts new file mode 100644 index 000000000000..d351a7136a84 --- /dev/null +++ b/src/dev-app/table/data.ts @@ -0,0 +1,804 @@ +import {MockedDataType} from './MockedDataType'; + +export const mockedData: MockedDataType[] = [ + { + id: 1, + first_name: 'Jillie', + last_name: 'Farrar', + email: 'jfarrar0@aol.com', + gender: 'Female', + ip_address: '213.199.76.217', + }, + { + id: 2, + first_name: 'Katrine', + last_name: 'Castle', + email: 'kcastle1@eventbrite.com', + gender: 'Female', + ip_address: '103.252.212.28', + }, + { + id: 3, + first_name: 'Lind', + last_name: 'Woods', + email: 'lwoods2@chicagotribune.com', + gender: 'Female', + ip_address: '33.121.164.255', + }, + { + id: 4, + first_name: 'Joli', + last_name: 'Jeff', + email: 'jjeff3@imgur.com', + gender: 'Non-binary', + ip_address: '135.10.191.181', + }, + { + id: 5, + first_name: 'Ches', + last_name: 'Pettman', + email: 'cpettman4@nydailynews.com', + gender: 'Male', + ip_address: '19.93.120.93', + }, + { + id: 6, + first_name: 'Bruno', + last_name: 'Hoston', + email: 'bhoston5@si.edu', + gender: 'Male', + ip_address: '81.86.226.200', + }, + { + id: 7, + first_name: 'Flori', + last_name: 'Yonge', + email: 'fyonge6@ehow.com', + gender: 'Female', + ip_address: '137.203.71.26', + }, + { + id: 8, + first_name: 'Vidovik', + last_name: 'Matveichev', + email: 'vmatveichev7@techcrunch.com', + gender: 'Male', + ip_address: '206.155.169.119', + }, + { + id: 9, + first_name: 'Kassie', + last_name: 'Rossbrooke', + email: 'krossbrooke8@hc360.com', + gender: 'Female', + ip_address: '252.250.191.83', + }, + { + id: 10, + first_name: 'Charmaine', + last_name: 'Hartright', + email: 'chartright9@tripod.com', + gender: 'Genderfluid', + ip_address: '77.251.64.223', + }, + { + id: 11, + first_name: 'Boyd', + last_name: 'Geaney', + email: 'bgeaneya@apache.org', + gender: 'Male', + ip_address: '137.255.185.155', + }, + { + id: 12, + first_name: 'Jerrome', + last_name: 'Bricksey', + email: 'jbrickseyb@g.co', + gender: 'Male', + ip_address: '117.245.228.240', + }, + { + id: 13, + first_name: 'Angus', + last_name: 'Paladino', + email: 'apaladinoc@mapquest.com', + gender: 'Male', + ip_address: '144.167.39.33', + }, + { + id: 14, + first_name: 'Lloyd', + last_name: 'Alcalde', + email: 'lalcalded@umn.edu', + gender: 'Male', + ip_address: '86.185.137.82', + }, + { + id: 15, + first_name: 'Lolly', + last_name: 'Roughley', + email: 'lroughleye@xinhuanet.com', + gender: 'Female', + ip_address: '97.93.184.11', + }, + { + id: 16, + first_name: 'Jermaine', + last_name: 'Raulston', + email: 'jraulstonf@studiopress.com', + gender: 'Male', + ip_address: '141.94.32.118', + }, + { + id: 17, + first_name: 'Chrisy', + last_name: 'Grummitt', + email: 'cgrummittg@people.com.cn', + gender: 'Male', + ip_address: '218.141.187.224', + }, + { + id: 18, + first_name: 'Conrad', + last_name: 'Gave', + email: 'cgaveh@berkeley.edu', + gender: 'Male', + ip_address: '113.212.12.78', + }, + { + id: 19, + first_name: 'Bethena', + last_name: 'Gaucher', + email: 'bgaucheri@desdev.cn', + gender: 'Female', + ip_address: '195.126.147.241', + }, + { + id: 20, + first_name: 'Bartholomew', + last_name: 'Drennan', + email: 'bdrennanj@technorati.com', + gender: 'Genderfluid', + ip_address: '56.122.186.122', + }, + { + id: 21, + first_name: 'Rod', + last_name: 'Spellsworth', + email: 'rspellsworthk@admin.ch', + gender: 'Male', + ip_address: '117.33.182.193', + }, + { + id: 22, + first_name: 'Joice', + last_name: 'Kensington', + email: 'jkensingtonl@java.com', + gender: 'Female', + ip_address: '168.102.163.118', + }, + { + id: 23, + first_name: 'Myriam', + last_name: 'Vasyanin', + email: 'mvasyaninm@ft.com', + gender: 'Female', + ip_address: '174.71.196.63', + }, + { + id: 24, + first_name: 'Maggy', + last_name: 'Houchen', + email: 'mhouchenn@nasa.gov', + gender: 'Female', + ip_address: '112.48.7.30', + }, + { + id: 25, + first_name: 'Jacenta', + last_name: 'Rennock', + email: 'jrennocko@cafepress.com', + gender: 'Female', + ip_address: '55.122.139.52', + }, + { + id: 26, + first_name: 'Layla', + last_name: 'Curlis', + email: 'lcurlisp@desdev.cn', + gender: 'Female', + ip_address: '201.68.7.0', + }, + { + id: 27, + first_name: 'Percy', + last_name: 'Woolvett', + email: 'pwoolvettq@sphinn.com', + gender: 'Polygender', + ip_address: '243.141.126.182', + }, + { + id: 28, + first_name: 'Cory', + last_name: 'Porcas', + email: 'cporcasr@pcworld.com', + gender: 'Male', + ip_address: '193.185.3.30', + }, + { + id: 29, + first_name: 'Engracia', + last_name: 'Weaving', + email: 'eweavings@huffingtonpost.com', + gender: 'Female', + ip_address: '134.192.254.58', + }, + { + id: 30, + first_name: 'Luci', + last_name: 'Grishagin', + email: 'lgrishagint@godaddy.com', + gender: 'Female', + ip_address: '133.2.63.99', + }, + { + id: 31, + first_name: 'Adrea', + last_name: 'Tyers', + email: 'atyersu@google.ca', + gender: 'Female', + ip_address: '94.15.22.94', + }, + { + id: 32, + first_name: 'Clem', + last_name: 'MacSwayde', + email: 'cmacswaydev@imageshack.us', + gender: 'Female', + ip_address: '145.21.120.5', + }, + { + id: 33, + first_name: 'Scarlet', + last_name: 'Sabey', + email: 'ssabeyw@diigo.com', + gender: 'Agender', + ip_address: '165.15.152.214', + }, + { + id: 34, + first_name: 'Hilly', + last_name: 'Shew', + email: 'hshewx@hostgator.com', + gender: 'Male', + ip_address: '189.59.56.196', + }, + { + id: 35, + first_name: 'Bartie', + last_name: 'Hendrickson', + email: 'bhendricksony@smugmug.com', + gender: 'Male', + ip_address: '119.235.114.107', + }, + { + id: 36, + first_name: 'Carroll', + last_name: 'Donalson', + email: 'cdonalsonz@imdb.com', + gender: 'Male', + ip_address: '118.184.41.11', + }, + { + id: 37, + first_name: 'Philly', + last_name: 'Meininger', + email: 'pmeininger10@nba.com', + gender: 'Female', + ip_address: '134.70.90.105', + }, + { + id: 38, + first_name: 'Langsdon', + last_name: 'Pinckney', + email: 'lpinckney11@wisc.edu', + gender: 'Male', + ip_address: '64.86.82.255', + }, + { + id: 39, + first_name: 'Sherill', + last_name: 'Burds', + email: 'sburds12@odnoklassniki.ru', + gender: 'Female', + ip_address: '47.131.116.152', + }, + { + id: 40, + first_name: 'Zach', + last_name: 'Verheyden', + email: 'zverheyden13@eventbrite.com', + gender: 'Non-binary', + ip_address: '43.114.29.31', + }, + { + id: 41, + first_name: 'Cindra', + last_name: 'Sealey', + email: 'csealey14@over-blog.com', + gender: 'Female', + ip_address: '185.60.188.151', + }, + { + id: 42, + first_name: 'Mella', + last_name: 'Reiling', + email: 'mreiling15@wikispaces.com', + gender: 'Female', + ip_address: '87.164.199.107', + }, + { + id: 43, + first_name: 'Karlie', + last_name: 'Spire', + email: 'kspire16@chicagotribune.com', + gender: 'Female', + ip_address: '63.192.143.181', + }, + { + id: 44, + first_name: 'Alaster', + last_name: 'Klimp', + email: 'aklimp17@youtube.com', + gender: 'Male', + ip_address: '219.118.177.100', + }, + { + id: 45, + first_name: 'Darrick', + last_name: 'Loadsman', + email: 'dloadsman18@toplist.cz', + gender: 'Male', + ip_address: '146.11.184.137', + }, + { + id: 46, + first_name: 'Paxton', + last_name: 'Mettetal', + email: 'pmettetal19@wiley.com', + gender: 'Male', + ip_address: '29.255.116.120', + }, + { + id: 47, + first_name: 'Kean', + last_name: 'Kneath', + email: 'kkneath1a@people.com.cn', + gender: 'Male', + ip_address: '158.164.2.141', + }, + { + id: 48, + first_name: 'Wenda', + last_name: 'Hammett', + email: 'whammett1b@java.com', + gender: 'Female', + ip_address: '243.147.199.199', + }, + { + id: 49, + first_name: 'Noach', + last_name: 'Haestier', + email: 'nhaestier1c@tripadvisor.com', + gender: 'Male', + ip_address: '13.3.115.218', + }, + { + id: 50, + first_name: 'Nobe', + last_name: 'Monan', + email: 'nmonan1d@skyrock.com', + gender: 'Male', + ip_address: '165.94.46.85', + }, + { + id: 51, + first_name: 'Rhianna', + last_name: 'Bush', + email: 'rbush1e@wp.com', + gender: 'Female', + ip_address: '145.239.65.185', + }, + { + id: 52, + first_name: 'Aldo', + last_name: 'Collete', + email: 'acollete1f@ezinearticles.com', + gender: 'Male', + ip_address: '239.33.188.101', + }, + { + id: 53, + first_name: 'Rasla', + last_name: 'Lassells', + email: 'rlassells1g@dmoz.org', + gender: 'Bigender', + ip_address: '153.106.16.92', + }, + { + id: 54, + first_name: 'Abe', + last_name: 'Matusovsky', + email: 'amatusovsky1h@reverbnation.com', + gender: 'Male', + ip_address: '247.151.104.155', + }, + { + id: 55, + first_name: 'Estrellita', + last_name: 'Feavyour', + email: 'efeavyour1i@hc360.com', + gender: 'Female', + ip_address: '7.224.29.254', + }, + { + id: 56, + first_name: 'Iorgos', + last_name: 'Dudhill', + email: 'idudhill1j@google.ru', + gender: 'Genderfluid', + ip_address: '168.40.247.147', + }, + { + id: 57, + first_name: 'Barclay', + last_name: 'Greenstock', + email: 'bgreenstock1k@auda.org.au', + gender: 'Male', + ip_address: '124.100.160.75', + }, + { + id: 58, + first_name: 'Yalonda', + last_name: 'Breissan', + email: 'ybreissan1l@cornell.edu', + gender: 'Female', + ip_address: '70.136.134.142', + }, + { + id: 59, + first_name: 'Grant', + last_name: 'Gehrtz', + email: 'ggehrtz1m@wufoo.com', + gender: 'Male', + ip_address: '244.49.2.15', + }, + { + id: 60, + first_name: 'Griz', + last_name: 'Oakhill', + email: 'goakhill1n@state.tx.us', + gender: 'Male', + ip_address: '67.2.239.137', + }, + { + id: 61, + first_name: 'Nadiya', + last_name: 'Swynfen', + email: 'nswynfen1o@businessweek.com', + gender: 'Female', + ip_address: '62.187.106.166', + }, + { + id: 62, + first_name: 'Vachel', + last_name: 'Corderoy', + email: 'vcorderoy1p@wikimedia.org', + gender: 'Male', + ip_address: '192.112.16.176', + }, + { + id: 63, + first_name: 'Spenser', + last_name: 'Muscroft', + email: 'smuscroft1q@blogtalkradio.com', + gender: 'Male', + ip_address: '199.90.56.187', + }, + { + id: 64, + first_name: 'Warde', + last_name: 'Leadbeater', + email: 'wleadbeater1r@histats.com', + gender: 'Male', + ip_address: '43.85.176.72', + }, + { + id: 65, + first_name: 'Phyllida', + last_name: 'Edger', + email: 'pedger1s@godaddy.com', + gender: 'Female', + ip_address: '227.102.79.68', + }, + { + id: 66, + first_name: 'Giuditta', + last_name: 'Cesconi', + email: 'gcesconi1t@icq.com', + gender: 'Female', + ip_address: '24.42.57.82', + }, + { + id: 67, + first_name: 'Jone', + last_name: 'Hearnes', + email: 'jhearnes1u@timesonline.co.uk', + gender: 'Male', + ip_address: '191.247.82.72', + }, + { + id: 68, + first_name: 'Aldwin', + last_name: 'Heggadon', + email: 'aheggadon1v@youku.com', + gender: 'Male', + ip_address: '97.179.100.52', + }, + { + id: 69, + first_name: 'Sauncho', + last_name: 'Schimke', + email: 'sschimke1w@clickbank.net', + gender: 'Male', + ip_address: '118.48.96.30', + }, + { + id: 70, + first_name: 'Cesar', + last_name: 'Brumfitt', + email: 'cbrumfitt1x@ameblo.jp', + gender: 'Male', + ip_address: '139.214.119.102', + }, + { + id: 71, + first_name: 'Leann', + last_name: 'Moatt', + email: 'lmoatt1y@huffingtonpost.com', + gender: 'Female', + ip_address: '241.162.190.170', + }, + { + id: 72, + first_name: 'Marie-jeanne', + last_name: 'Lundy', + email: 'mlundy1z@acquirethisname.com', + gender: 'Female', + ip_address: '37.133.92.198', + }, + { + id: 73, + first_name: 'Cathe', + last_name: 'Hegden', + email: 'chegden20@angelfire.com', + gender: 'Female', + ip_address: '154.57.208.216', + }, + { + id: 74, + first_name: 'Katerine', + last_name: 'Marquese', + email: 'kmarquese21@i2i.jp', + gender: 'Female', + ip_address: '231.139.179.39', + }, + { + id: 75, + first_name: 'Wendie', + last_name: 'Nisbet', + email: 'wnisbet22@networksolutions.com', + gender: 'Female', + ip_address: '248.18.185.39', + }, + { + id: 76, + first_name: 'Eryn', + last_name: 'Valentim', + email: 'evalentim23@hp.com', + gender: 'Female', + ip_address: '105.114.109.36', + }, + { + id: 77, + first_name: 'Colette', + last_name: 'Morrallee', + email: 'cmorrallee24@bbc.co.uk', + gender: 'Female', + ip_address: '190.22.92.238', + }, + { + id: 78, + first_name: 'Ferdinanda', + last_name: 'Smorthwaite', + email: 'fsmorthwaite25@epa.gov', + gender: 'Female', + ip_address: '183.77.225.118', + }, + { + id: 79, + first_name: 'Leshia', + last_name: 'Huckerbe', + email: 'lhuckerbe26@booking.com', + gender: 'Female', + ip_address: '213.253.87.2', + }, + { + id: 80, + first_name: 'Barbra', + last_name: 'Breinlein', + email: 'bbreinlein27@issuu.com', + gender: 'Female', + ip_address: '53.38.93.202', + }, + { + id: 81, + first_name: 'Doretta', + last_name: 'Shambroke', + email: 'dshambroke28@dropbox.com', + gender: 'Female', + ip_address: '131.237.237.3', + }, + { + id: 82, + first_name: 'Bernardo', + last_name: 'Jury', + email: 'bjury29@hibu.com', + gender: 'Male', + ip_address: '53.37.39.108', + }, + { + id: 83, + first_name: 'Katerina', + last_name: 'Butfield', + email: 'kbutfield2a@craigslist.org', + gender: 'Female', + ip_address: '113.65.238.101', + }, + { + id: 84, + first_name: 'Melba', + last_name: 'Agass', + email: 'magass2b@ca.gov', + gender: 'Agender', + ip_address: '221.21.58.159', + }, + { + id: 85, + first_name: 'Sidnee', + last_name: 'Southouse', + email: 'ssouthouse2c@ucla.edu', + gender: 'Male', + ip_address: '196.2.147.165', + }, + { + id: 86, + first_name: 'Cassaundra', + last_name: 'Klees', + email: 'cklees2d@nbcnews.com', + gender: 'Female', + ip_address: '111.130.90.159', + }, + { + id: 87, + first_name: 'Nellie', + last_name: 'Brook', + email: 'nbrook2e@oaic.gov.au', + gender: 'Female', + ip_address: '236.123.217.177', + }, + { + id: 88, + first_name: 'Kinny', + last_name: 'Meagher', + email: 'kmeagher2f@jugem.jp', + gender: 'Male', + ip_address: '195.68.66.119', + }, + { + id: 89, + first_name: 'Winona', + last_name: 'Ralphs', + email: 'wralphs2g@guardian.co.uk', + gender: 'Female', + ip_address: '32.31.129.240', + }, + { + id: 90, + first_name: 'Rafi', + last_name: 'Galley', + email: 'rgalley2h@cbsnews.com', + gender: 'Male', + ip_address: '69.165.110.111', + }, + { + id: 91, + first_name: 'Clem', + last_name: 'Broose', + email: 'cbroose2i@ucsd.edu', + gender: 'Female', + ip_address: '213.42.186.195', + }, + { + id: 92, + first_name: 'Sherman', + last_name: 'Osmint', + email: 'sosmint2j@a8.net', + gender: 'Male', + ip_address: '210.89.224.167', + }, + { + id: 93, + first_name: 'Linell', + last_name: 'Sinney', + email: 'lsinney2k@trellian.com', + gender: 'Female', + ip_address: '65.73.37.29', + }, + { + id: 94, + first_name: 'Benyamin', + last_name: 'Hurll', + email: 'bhurll2l@ovh.net', + gender: 'Male', + ip_address: '140.213.102.251', + }, + { + id: 95, + first_name: 'Nicko', + last_name: "O'Donegan", + email: 'nodonegan2m@economist.com', + gender: 'Male', + ip_address: '124.211.52.90', + }, + { + id: 96, + first_name: 'Werner', + last_name: 'Mandeville', + email: 'wmandeville2n@apache.org', + gender: 'Male', + ip_address: '165.71.227.113', + }, + { + id: 97, + first_name: 'Evvy', + last_name: 'Denisyev', + email: 'edenisyev2o@meetup.com', + gender: 'Non-binary', + ip_address: '73.155.89.89', + }, + { + id: 98, + first_name: 'Rabi', + last_name: 'Bulfield', + email: 'rbulfield2p@tinypic.com', + gender: 'Male', + ip_address: '119.157.11.193', + }, + { + id: 99, + first_name: 'Cora', + last_name: 'Lauchlan', + email: 'clauchlan2q@cdc.gov', + gender: 'Female', + ip_address: '198.176.50.130', + }, + { + id: 100, + first_name: 'Lacey', + last_name: 'Raggitt', + email: 'lraggitt2r@zdnet.com', + gender: 'Female', + ip_address: '205.187.194.112', + }, +]; diff --git a/src/dev-app/table/paged-data-source.ts b/src/dev-app/table/paged-data-source.ts new file mode 100644 index 000000000000..5d54c4ffe209 --- /dev/null +++ b/src/dev-app/table/paged-data-source.ts @@ -0,0 +1,89 @@ +import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; +import {Observable} from 'rxjs'; +import {PagedTableDataSourceNextPageData} from './PagedTableDataSourceNextPageData'; +import {PagedTableDataSourceConfig} from './PagedTableDataSourceConfig'; +import {CollectionViewer} from '@angular/cdk/collections'; +import {TableDataSource} from './table-data-source'; + +export class PagedDataSource extends TableDataSource { + protected _nextPageToken?: string; + protected _nextPageHandler?: ( + pageSize: number, + nextPageNumber: number, + nextPageToken?: string, + ) => Observable>; + + private _pageSize: number; + private _itemsUntilReq: number; + private _currentPage: number = 0; + + constructor(config: PagedTableDataSourceConfig) { + super(config); + this._pageSize = config?.pageSize ?? 40; + this._itemsUntilReq = config.itemsUntilReq ?? 5; + this.setNextPageHandler(config.nextPageHandler); + } + + override connect(collectionViewer: CollectionViewer): Observable { + collectionViewer.viewChange.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(range => { + if (!this._pageSize) { + throw new Error(`[PagedDataSource][connect] pageSize is not defined`); + } + + console.log(range); + const nextPageThreshold = this._currentPage * this._pageSize - this._itemsUntilReq; + const isNextPageThresholdReached = range.end > nextPageThreshold; + + if (isNextPageThresholdReached && !this.isListEndReached && !this.isLoading) { + this.loadNextPage(); + } + }); + + return super.connect(collectionViewer); + } + + loadNextPage(): void { + if (!this._pageSize) { + throw new Error(`[PagedDataSource][loadNextPage] pageSize is not defined`); + } + + if (!this._nextPageHandler) { + throw new Error(`[PagedDataSource][loadNextPage] _nextPageHandler is not defined`); + } + + this.isLoading = true; + this._nextPageHandler(this._pageSize, this._currentPage + 1, this._nextPageToken) + .pipe(takeUntilDestroyed(this._destroyRef)) + .subscribe((nextPageData: PagedTableDataSourceNextPageData) => { + if (!this._pageSize) { + throw new Error(`[PagedDataSource][_nextPageHandler] pageSize is not defined`); + } + + this._currentPage++; + this.setNextPageToken(nextPageData.nextPageToken); + this.setData(this.getData().concat(nextPageData.content)); + + this.isLoading = false; + + if (nextPageData.content.length < this._pageSize) { + this.isListEndReached = true; + } + }); + } + + resetData(): void { + this._currentPage = 0; + this.isListEndReached = false; + + this.setData([]); + delete this._nextPageToken; + } + + setNextPageHandler(nextPageHandler: typeof this._nextPageHandler): void { + this._nextPageHandler = nextPageHandler; + } + + setNextPageToken(nextPageToken?: string): void { + this._nextPageToken = nextPageToken; + } +} diff --git a/src/dev-app/table/table-data-source.ts b/src/dev-app/table/table-data-source.ts new file mode 100644 index 000000000000..8d71f6915509 --- /dev/null +++ b/src/dev-app/table/table-data-source.ts @@ -0,0 +1,34 @@ +import {CollectionViewer, DataSource} from '@angular/cdk/collections'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {DestroyRef, inject} from '@angular/core'; +import {TableDataSourceConfig} from './TableDataSourceConfig'; + +export class TableDataSource extends DataSource { + protected readonly _destroyRef: DestroyRef = inject(DestroyRef); + + data$ = new BehaviorSubject([]); + + itemSize: number; + + isLoading: boolean = false; + isListEndReached: boolean = false; + + constructor(config?: TableDataSourceConfig) { + super(); + this.itemSize = config?.itemSize ?? 46; + } + + setData(data: T[]): void { + this.data$.next(data); + } + + getData(): T[] { + return this.data$.getValue(); + } + + connect(collectionViewer: CollectionViewer): Observable { + return this.data$; + } + + disconnect(): void {} +} diff --git a/src/dev-app/table/table-demo.html b/src/dev-app/table/table-demo.html index 3d1e98d2ccc4..a2050b0e4e26 100644 --- a/src/dev-app/table/table-demo.html +++ b/src/dev-app/table/table-demo.html @@ -1,95 +1,60 @@ -

CDK table basic

- - -

CDK table with recycled rows

- - -

CDK table basic with fixed column widths

- - -

CDK table basic flex

- - -

CDK table with virtual scrolling

- - -

Table basic

- - -

Table basic with recycled rows

- - -

Table basic flex

- - -

Table flex with large row

- - -

Table dynamic columns

- - -

Table expandable rows

- - -

Table filtering

- - -

Table footer row

- - -

Table with http

- - -

Table with multiple headers and footers

- - -

Table overview

- - -

Table row context

- - -

Table with pagination

- - -

Table with virtual scrolling

- - -

Table with selection

- - -

Table with sorting

- - -

Table with sticky columns

- - -

Table with sticky headers, footers and columns

- - -

Table flex with sticky headers, footers and columns

- - -

Table with sticky footer

- - -

Table with sticky header

- - -

Table with multiple rows per data item

- - -

Table with mat-text-column

- - -

Table with mat-text-column advanced

- - -

Table wrapped in reusable component

- - -

Table wrapped re-orderable columns

- - -

Table wrapped re-orderable rows

- +

Showing {{dataSource.getData().length}} rows

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Id + {{ element.id }} + First name + {{ element.first_name }} + Last name + {{ element.last_name }} + Email + {{ element.email }} + Gender + {{ element.gender }} + IP Address + {{element.ip_address}} +
+
+ +@if (dataSource.isLoading) { +
loading...
+} diff --git a/src/dev-app/table/table-demo.ts b/src/dev-app/table/table-demo.ts index 0cf758276588..7a7675af4b3e 100644 --- a/src/dev-app/table/table-demo.ts +++ b/src/dev-app/table/table-demo.ts @@ -7,79 +7,100 @@ */ import {ChangeDetectionStrategy, Component} from '@angular/core'; -import { - CdkTableBasicExample, - CdkTableFixedLayoutExample, - CdkTableFlexBasicExample, - CdkTableRecycleRowsExample, - CdkTableVirtualScrollExample, -} from '@angular/components-examples/cdk/table'; -import { - TableBasicExample, - TableDragDropExample, - TableDynamicColumnsExample, - TableExpandableRowsExample, - TableFilteringExample, - TableFlexBasicExample, - TableFlexLargeRowExample, - TableFooterRowExample, - TableHttpExample, - TableMultipleHeaderFooterExample, - TableMultipleRowTemplateExample, - TableOverviewExample, - TablePaginationExample, - TableRecycleRowsExample, - TableReorderableExample, - TableRowContextExample, - TableSelectionExample, - TableSortingExample, - TableStickyColumnsExample, - TableStickyComplexExample, - TableStickyComplexFlexExample, - TableStickyFooterExample, - TableStickyHeaderExample, - TableTextColumnAdvancedExample, - TableTextColumnExample, - TableVirtualScrollExample, - TableWrappedExample, -} from '@angular/components-examples/material/table'; +import {MatTableModule} from '@angular/material/table'; +import {ScrollingModule} from '@angular/cdk/scrolling'; +import {MockedDataType} from './MockedDataType'; +import {TableDataSource} from './table-data-source'; +import {mockedData} from './data'; +import {TableColumn} from './TableExampleColumn'; +import {PagedTableDataSourceNextPageData} from './PagedTableDataSourceNextPageData'; +import {Observable, of} from 'rxjs'; +import {delay, map} from 'rxjs/operators'; +import {PagedDataSource} from './paged-data-source'; + +export const TABLE_EXAMPLE_COLUMNS: readonly TableColumn[] = [ + TableColumn.ID, + TableColumn.FIRST_NAME, + TableColumn.LAST_NAME, + // TableColumn.EMAIL, + // TableColumn.GENDER, + // TableColumn.IP_ADDRESS, +]; @Component({ templateUrl: './table-demo.html', - imports: [ - CdkTableFlexBasicExample, - CdkTableBasicExample, - CdkTableFixedLayoutExample, - CdkTableRecycleRowsExample, - CdkTableVirtualScrollExample, - TableFlexBasicExample, - TableBasicExample, - TableDynamicColumnsExample, - TableExpandableRowsExample, - TableFilteringExample, - TableFooterRowExample, - TableHttpExample, - TableMultipleHeaderFooterExample, - TableMultipleRowTemplateExample, - TableOverviewExample, - TablePaginationExample, - TableVirtualScrollExample, - TableRowContextExample, - TableSelectionExample, - TableSortingExample, - TableStickyColumnsExample, - TableStickyComplexFlexExample, - TableStickyComplexExample, - TableStickyFooterExample, - TableStickyHeaderExample, - TableTextColumnAdvancedExample, - TableTextColumnExample, - TableWrappedExample, - TableReorderableExample, - TableRecycleRowsExample, - TableFlexLargeRowExample, - TableDragDropExample, - ], + imports: [MatTableModule, ScrollingModule], changeDetection: ChangeDetectionStrategy.OnPush, + styles: ` + .example-container { + height: 600px; + overflow: auto; + } + + .example-container table { + width: 100%; + } + + .loading { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: white; + background: rgba(0, 0, 0, 0.8); + } + + :host { + position: relative; + } + + td { + white-space: nowrap; + } + + `, }) -export class TableDemo {} +export class TableDemo { + readonly TableExampleColumn = TableColumn; + + displayedColumns: string[] = [...TABLE_EXAMPLE_COLUMNS]; + dataSource!: TableDataSource; + + trackBy = (index: number, el: MockedDataType) => el.id; + + constructor() { + this.initStaticDataSource(); // static data, comment the other one + // this.initPagedDataSource(); // async data, comment the other one + } + + initStaticDataSource(): void { + this.dataSource = new TableDataSource(); + this.dataSource.setData(mockedData); + } + + initPagedDataSource(): void { + this.dataSource = new PagedDataSource({ + pageSize: 40, + itemsUntilReq: 5, + nextPageHandler: this._nextPageHandler.bind(this), + }); + } + + private _nextPageHandler( + pageSize: number, + nextPageNumber: number, + nextPageToken?: string, + ): Observable> { + return of(mockedData).pipe( + delay(1000), + map((data: MockedDataType[]) => ({ + content: data.slice(pageSize * (nextPageNumber - 1), pageSize * nextPageNumber), + nextPageToken, + })), + ); + } +}