mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-09 19:22:51 +00:00
122
src/app/modules/data/data-facets.provider.spec.ts
Normal file
122
src/app/modules/data/data-facets.provider.spec.ts
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018, 2019 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {SCFacet, SCThing} from '@openstapps/core';
|
||||||
|
import {sampleAggregations} from '../../_helpers/data/sampleConfiguration';
|
||||||
|
import {sampleThingsMap} from '../../_helpers/data/sampleThings';
|
||||||
|
import {DataFacetsProvider} from './data-facets.provider';
|
||||||
|
import {DataModule} from './data.module';
|
||||||
|
import {DataProvider} from './data.provider';
|
||||||
|
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
||||||
|
|
||||||
|
describe('DataProvider', () => {
|
||||||
|
let dataFacetsProvider: DataFacetsProvider;
|
||||||
|
const sampleFacets: SCFacet[] = [
|
||||||
|
{
|
||||||
|
buckets: [{education: 4}, {learn: 3}, {computer: 3}],
|
||||||
|
field: 'categories',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buckets: [{'Major One': 1}, {'Major Two': 2}, {'Major Three': 1}],
|
||||||
|
field: 'majors',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buckets: [{building: 3}, {room: 7}],
|
||||||
|
field: 'type',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const sampleFacetsMap: {[key: string]: {[key: string]: number}} = {
|
||||||
|
categories: {education: 4, learn: 3, computer: 3},
|
||||||
|
majors: {'Major One': 1, 'Major Two': 2, 'Major Three': 1},
|
||||||
|
type: {building: 3, room: 7},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sampleItems: SCThing[] = [
|
||||||
|
...sampleThingsMap.building,
|
||||||
|
...sampleThingsMap.person,
|
||||||
|
...sampleThingsMap.room,
|
||||||
|
...sampleThingsMap['academic event'],
|
||||||
|
];
|
||||||
|
|
||||||
|
const sampleBuckets: Array<{[key: string]: number}> = [{foo: 1}, {bar: 2}, {'foo bar': 3}];
|
||||||
|
const sampleBucketsMap: {[key: string]: number} = {foo: 1, bar: 2, 'foo bar': 3};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [DataModule],
|
||||||
|
providers: [
|
||||||
|
DataProvider,
|
||||||
|
StAppsWebHttpClient,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
dataFacetsProvider = TestBed.get(DataFacetsProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add buckets properly', () => {
|
||||||
|
let bucketsMap: {[key: string]: number} = {};
|
||||||
|
bucketsMap = dataFacetsProvider.addBuckets(bucketsMap, ['foo']);
|
||||||
|
expect(bucketsMap).toEqual({foo: 1});
|
||||||
|
|
||||||
|
bucketsMap = dataFacetsProvider.addBuckets(bucketsMap, ['foo']);
|
||||||
|
expect(bucketsMap).toEqual({foo: 2});
|
||||||
|
|
||||||
|
bucketsMap = dataFacetsProvider.addBuckets(bucketsMap, ['bar']);
|
||||||
|
expect(bucketsMap).toEqual({foo: 2, bar: 1});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert buckets to buckets map', () => {
|
||||||
|
expect(dataFacetsProvider.bucketsToMap(sampleBuckets)).toEqual(sampleBucketsMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert buckets map into buckets', () => {
|
||||||
|
expect(dataFacetsProvider.mapToBuckets(sampleBucketsMap)).toEqual(sampleBuckets);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert facets into a facets map', () => {
|
||||||
|
expect(dataFacetsProvider.facetsToMap(sampleFacets)).toEqual(sampleFacetsMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert facets map into facets', () => {
|
||||||
|
expect(dataFacetsProvider.mapToFacets(sampleFacetsMap)).toEqual(sampleFacets);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract facets (and append them if needed) from the data', () => {
|
||||||
|
const sampleCombinedFacets: SCFacet[] = [
|
||||||
|
{
|
||||||
|
buckets: [{computer: 3}, {course: 1}, {education: 5}, {learn: 3}, {library: 1}, {practicum: 1}],
|
||||||
|
field: 'categories',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buckets: [{'Major One': 2}, {'Major Two': 4}, {'Major Three': 2}],
|
||||||
|
field: 'majors',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
buckets: [{building: 4}, {'academic event': 2}, {person: 2}, {room: 8}],
|
||||||
|
field: 'type',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const checkEqual = (expected: SCFacet[], actual: SCFacet[]) => {
|
||||||
|
const expectedMap = dataFacetsProvider.facetsToMap(expected);
|
||||||
|
const actualMap = dataFacetsProvider.facetsToMap(actual);
|
||||||
|
Object.keys(actualMap).forEach((key) => {
|
||||||
|
Object.keys(actualMap[key]).forEach((subKey) => {
|
||||||
|
expect(actualMap[key][subKey]).toBe(expectedMap[key][subKey]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
checkEqual(dataFacetsProvider.extractFacets(sampleItems, sampleAggregations, sampleFacets), sampleCombinedFacets);
|
||||||
|
});
|
||||||
|
});
|
||||||
152
src/app/modules/data/data-facets.provider.ts
Normal file
152
src/app/modules/data/data-facets.provider.ts
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018, 2019 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {SCBackendAggregationConfiguration, SCFacet, SCThing} from '@openstapps/core';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DataFacetsProvider {
|
||||||
|
// tslint:disable-next-line:no-empty
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds buckets to a map of buckets (e.g. if a buckets array is [{foo: 1}, {bar: 3}],
|
||||||
|
* its bucketsMap is {foo: 1, bar: 3}), if a field 'bar' is added to it it becomes:
|
||||||
|
* {foo: 1, bar: 4}
|
||||||
|
*
|
||||||
|
* @param bucketsMap Buckets array transformed into a map
|
||||||
|
* @param fields A field that should be added to buckets (its map)
|
||||||
|
*/
|
||||||
|
addBuckets(bucketsMap: {[key: string]: number}, fields: string[]): {[key: string]: number} {
|
||||||
|
fields.forEach((field) => {
|
||||||
|
if (typeof bucketsMap[field] !== 'undefined') {
|
||||||
|
bucketsMap[field] = bucketsMap[field] + 1;
|
||||||
|
} else {
|
||||||
|
bucketsMap[field] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return bucketsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a buckets array to a map
|
||||||
|
*
|
||||||
|
* @param buckets Buckets from a facet
|
||||||
|
*/
|
||||||
|
bucketsToMap(buckets: Array<{[key: string]: number}>): {[key: string]: number} {
|
||||||
|
const bucketsMap: {[key: string]: number} = {};
|
||||||
|
buckets.forEach((bucket) => {
|
||||||
|
for (const key in bucket) {
|
||||||
|
if (bucket.hasOwnProperty(key)) {
|
||||||
|
bucketsMap[key] = bucket[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return bucketsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a buckets map into buckets array (as it is inside of a facet)
|
||||||
|
*
|
||||||
|
* @param bucketsMap A map from a buckets array
|
||||||
|
*/
|
||||||
|
mapToBuckets(bucketsMap: {[key: string]: number}): Array<{[key: string]: number}> {
|
||||||
|
const buckets: Array<{[key: string]: number}> = [];
|
||||||
|
for (const key in bucketsMap) {
|
||||||
|
if (bucketsMap.hasOwnProperty(key)) {
|
||||||
|
const bucket: {[key: string]: number} = {};
|
||||||
|
bucket[key] = bucketsMap[key];
|
||||||
|
buckets.push(bucket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts facets array into a map (for quicker operations with facets)
|
||||||
|
*
|
||||||
|
* @param facets Array of facets
|
||||||
|
*/
|
||||||
|
facetsToMap(facets: SCFacet[]): {[key: string]: {[key: string]: number}} {
|
||||||
|
const facetsMap: {[key: string]: {[key: string]: number}} = {};
|
||||||
|
facets.forEach((facet) => {
|
||||||
|
facetsMap[facet.field] = this.bucketsToMap(facet.buckets);
|
||||||
|
});
|
||||||
|
return facetsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts facets map into an array of facets (as they are provided by backend)
|
||||||
|
*
|
||||||
|
* @param facetsMap A map from facets array
|
||||||
|
*/
|
||||||
|
mapToFacets(facetsMap: {[key: string]: {[key: string]: number}}): SCFacet[] {
|
||||||
|
const facets: SCFacet[] = [];
|
||||||
|
for (const key in facetsMap) {
|
||||||
|
if (facetsMap.hasOwnProperty(key)) {
|
||||||
|
const facet: SCFacet = {buckets: [], field: ''};
|
||||||
|
facet.field = key;
|
||||||
|
facet.buckets = this.mapToBuckets(facetsMap[key]);
|
||||||
|
facets.push(facet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return facets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract facets from data items, optionally combine them with a list of existing facets
|
||||||
|
*
|
||||||
|
* @param items Items to extract facets from
|
||||||
|
* @param aggregations Aggregations configuration(s) from backend
|
||||||
|
* @param facets Existing facets to be combined with the facets from the items
|
||||||
|
*/
|
||||||
|
extractFacets(
|
||||||
|
items: SCThing[],
|
||||||
|
aggregations: SCBackendAggregationConfiguration[],
|
||||||
|
facets: SCFacet[] = []): SCFacet[] {
|
||||||
|
if (items.length === 0) {
|
||||||
|
if (facets.length === 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return facets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const combinedFacets: SCFacet[] = facets;
|
||||||
|
const combinedFacetsMap: {[key: string]: {[key: string]: number}} = this.facetsToMap(combinedFacets);
|
||||||
|
(items as any[]).forEach((item) => {
|
||||||
|
aggregations.forEach((aggregation) => {
|
||||||
|
let fieldValues: string | string[] = item[aggregation.fieldName];
|
||||||
|
if (typeof fieldValues === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof fieldValues === 'string') {
|
||||||
|
fieldValues = [fieldValues];
|
||||||
|
}
|
||||||
|
if (typeof aggregation.onlyOnTypes === 'undefined') {
|
||||||
|
combinedFacetsMap[aggregation.fieldName] = this.addBuckets(
|
||||||
|
combinedFacetsMap[aggregation.fieldName] || {},
|
||||||
|
fieldValues,
|
||||||
|
);
|
||||||
|
} else if (aggregation.onlyOnTypes.indexOf(item.type) !== -1) {
|
||||||
|
combinedFacetsMap[aggregation.fieldName] = this.addBuckets(
|
||||||
|
combinedFacetsMap[aggregation.fieldName] || {},
|
||||||
|
fieldValues,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return this.mapToFacets(combinedFacetsMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import {FormsModule} from '@angular/forms';
|
|||||||
import {IonicModule} from '@ionic/angular';
|
import {IonicModule} from '@ionic/angular';
|
||||||
import {TranslateModule} from '@ngx-translate/core';
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
import {StorageModule} from '../storage/storage.module';
|
import {StorageModule} from '../storage/storage.module';
|
||||||
|
import {DataFacetsProvider} from './data-facets.provider';
|
||||||
import {DataRoutingModule} from './data-routing.module';
|
import {DataRoutingModule} from './data-routing.module';
|
||||||
import {DataProvider} from './data.provider';
|
import {DataProvider} from './data.provider';
|
||||||
import {DataDetailComponent} from './detail/data-detail.component';
|
import {DataDetailComponent} from './detail/data-detail.component';
|
||||||
@@ -55,6 +56,7 @@ import {EventListItemComponent} from './types/event/event-list-item.component';
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
DataProvider,
|
DataProvider,
|
||||||
|
DataFacetsProvider,
|
||||||
StAppsWebHttpClient,
|
StAppsWebHttpClient,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
*/
|
*/
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {Client} from '@openstapps/api/lib/client';
|
import {Client} from '@openstapps/api/lib/client';
|
||||||
import {SCMessage, SCSaveableThing, SCSearchQuery, SCSearchResponse,
|
import {SCDish, SCMessage, SCSaveableThing, SCSearchQuery,
|
||||||
SCSearchValueFilter, SCThing, SCThingOriginType, SCThings, SCThingType} from '@openstapps/core';
|
SCSearchResponse, SCSearchValueFilter, SCThing, SCThingOriginType, SCThings, SCThingType} from '@openstapps/core';
|
||||||
|
import {sampleThingsMap} from '../../_helpers/data/sampleThings';
|
||||||
import {StorageProvider} from '../storage/storage.provider';
|
import {StorageProvider} from '../storage/storage.provider';
|
||||||
import {DataModule} from './data.module';
|
import {DataModule} from './data.module';
|
||||||
import {DataProvider, DataScope} from './data.provider';
|
import {DataProvider, DataScope} from './data.provider';
|
||||||
@@ -24,31 +25,9 @@ import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
|||||||
describe('DataProvider', () => {
|
describe('DataProvider', () => {
|
||||||
let dataProvider: DataProvider;
|
let dataProvider: DataProvider;
|
||||||
let storageProvider: StorageProvider;
|
let storageProvider: StorageProvider;
|
||||||
|
const sampleThing: SCMessage = sampleThingsMap.message[0] as SCMessage;
|
||||||
const sampleResponse: SCSearchResponse = {
|
const sampleResponse: SCSearchResponse = {
|
||||||
data: [
|
data: sampleThingsMap.dish as SCDish[],
|
||||||
{
|
|
||||||
categories: ['main dish'],
|
|
||||||
name: 'foo dish',
|
|
||||||
origin: {
|
|
||||||
indexed: '12345',
|
|
||||||
name: 'bar',
|
|
||||||
type: SCThingOriginType.Remote,
|
|
||||||
},
|
|
||||||
type: SCThingType.Dish,
|
|
||||||
uid: '123',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
categories: ['dessert'],
|
|
||||||
name: 'foo dessert',
|
|
||||||
origin: {
|
|
||||||
indexed: '12345',
|
|
||||||
name: 'bar',
|
|
||||||
type: SCThingOriginType.Remote,
|
|
||||||
},
|
|
||||||
type: SCThingType.Dish,
|
|
||||||
uid: '123',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
facets: [
|
facets: [
|
||||||
{
|
{
|
||||||
buckets: [],
|
buckets: [],
|
||||||
@@ -75,18 +54,6 @@ describe('DataProvider', () => {
|
|||||||
filter: sampleFilter,
|
filter: sampleFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
const sampleThing: SCMessage = {
|
|
||||||
audiences: ['students'],
|
|
||||||
message: 'Foo Message',
|
|
||||||
name: 'foo',
|
|
||||||
origin: {
|
|
||||||
indexed: 'SOME-DATE',
|
|
||||||
name: 'some name',
|
|
||||||
type: SCThingOriginType.Remote,
|
|
||||||
},
|
|
||||||
type: SCThingType.Message,
|
|
||||||
uid: '123',
|
|
||||||
};
|
|
||||||
const sampleSavable: SCSaveableThing<SCThings> = {
|
const sampleSavable: SCSaveableThing<SCThings> = {
|
||||||
data: sampleThing,
|
data: sampleThing,
|
||||||
name: sampleThing.name,
|
name: sampleThing.name,
|
||||||
@@ -97,7 +64,7 @@ describe('DataProvider', () => {
|
|||||||
type: SCThingType.Message,
|
type: SCThingType.Message,
|
||||||
uid: sampleThing.uid,
|
uid: sampleThing.uid,
|
||||||
};
|
};
|
||||||
const otherSampleThing: SCMessage = {...sampleThing, uid: '456', name: 'bar'};
|
const otherSampleThing: SCMessage = {...sampleThing, uid: 'message-456', name: 'bar'};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
|||||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
import {ActivatedRoute, RouterModule} from '@angular/router';
|
import {ActivatedRoute, RouterModule} from '@angular/router';
|
||||||
import {IonRefresher} from '@ionic/angular';
|
import {IonRefresher} from '@ionic/angular';
|
||||||
import {SCMessage, SCThingOriginType, SCThingType} from '@openstapps/core';
|
import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {sampleThingsMap} from '../../../_helpers/data/sampleThings';
|
||||||
import {DataRoutingModule} from '../data-routing.module';
|
import {DataRoutingModule} from '../data-routing.module';
|
||||||
import {DataModule} from '../data.module';
|
import {DataModule} from '../data.module';
|
||||||
import {DataProvider} from '../data.provider';
|
import {DataProvider} from '../data.provider';
|
||||||
import {DataDetailComponent} from './data-detail.component';
|
import {DataDetailComponent} from './data-detail.component';
|
||||||
import {TranslateModule, TranslateLoader, TranslateFakeLoader} from '@ngx-translate/core';
|
|
||||||
|
|
||||||
describe('DataDetailComponent', () => {
|
describe('DataDetailComponent', () => {
|
||||||
let comp: DataDetailComponent;
|
let comp: DataDetailComponent;
|
||||||
@@ -29,25 +29,13 @@ describe('DataDetailComponent', () => {
|
|||||||
let detailPage: HTMLElement;
|
let detailPage: HTMLElement;
|
||||||
let dataProvider: DataProvider;
|
let dataProvider: DataProvider;
|
||||||
let refresher: IonRefresher;
|
let refresher: IonRefresher;
|
||||||
|
const sampleThing = sampleThingsMap.message[0];
|
||||||
|
|
||||||
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
||||||
// class DataListItemComponent {
|
// class DataListItemComponent {
|
||||||
// @Input() item;
|
// @Input() item;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const sampleThing: SCMessage = {
|
|
||||||
audiences: ['students'],
|
|
||||||
message: 'Foo Message',
|
|
||||||
name: 'foo',
|
|
||||||
origin: {
|
|
||||||
indexed: 'SOME-DATE',
|
|
||||||
name: 'some name',
|
|
||||||
type: SCThingOriginType.Remote,
|
|
||||||
},
|
|
||||||
type: SCThingType.Message,
|
|
||||||
uid: '123',
|
|
||||||
};
|
|
||||||
|
|
||||||
const fakeActivatedRoute = {
|
const fakeActivatedRoute = {
|
||||||
snapshot: {
|
snapshot: {
|
||||||
paramMap: {
|
paramMap: {
|
||||||
|
|||||||
@@ -36,8 +36,11 @@ export class DataListComponent {
|
|||||||
|
|
||||||
loading: HTMLIonLoadingElement;
|
loading: HTMLIonLoadingElement;
|
||||||
|
|
||||||
// tslint:disable-next-line:max-line-length
|
constructor(
|
||||||
constructor(private loadingController: LoadingController, private alertController: AlertController, dataProvider: DataProvider) {
|
private loadingController: LoadingController,
|
||||||
|
private alertController: AlertController,
|
||||||
|
dataProvider: DataProvider,
|
||||||
|
) {
|
||||||
this.dataProvider = dataProvider;
|
this.dataProvider = dataProvider;
|
||||||
this.queryChanged
|
this.queryChanged
|
||||||
.pipe(
|
.pipe(
|
||||||
@@ -84,15 +87,13 @@ export class DataListComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadMore(event: any): Promise<any> {
|
async loadMore(event: any): Promise<void> {
|
||||||
this.from += this.size;
|
this.from += this.size;
|
||||||
await this.fetchItems();
|
await this.fetchItems();
|
||||||
event.target.complete();
|
event.target.complete();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query: string) {
|
search(query: string) {
|
||||||
this.queryChanged.next(query);
|
this.queryChanged.next(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user