@@ -9,28 +9,31 @@ import {
99 Output ,
1010 ViewChild
1111} from '@angular/core' ;
12- import { debounceTime , distinctUntilChanged , map , switchMap , take , tap } from 'rxjs/operators' ;
12+ import { debounceTime , map , startWith , switchMap , take , tap } from 'rxjs/operators' ;
1313import { followLink } from '../../../shared/utils/follow-link-config.model' ;
1414import {
1515 getAllSucceededRemoteData ,
1616 getFirstCompletedRemoteData ,
1717 metadataFieldsToString
1818} from '../../../core/shared/operators' ;
19- import { Observable } from 'rxjs/internal/Observable' ;
19+ import {
20+ BehaviorSubject ,
21+ combineLatest as observableCombineLatest ,
22+ Observable ,
23+ of ,
24+ Subscription ,
25+ } from 'rxjs' ;
2026import { RegistryService } from '../../../core/registry/registry.service' ;
2127import { UntypedFormControl } from '@angular/forms' ;
22- import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject' ;
2328import { hasValue } from '../../../shared/empty.util' ;
24- import { Subscription } from 'rxjs/internal/Subscription' ;
25- import { of } from 'rxjs/internal/observable/of' ;
2629import { NotificationsService } from '../../../shared/notifications/notifications.service' ;
2730import { TranslateService } from '@ngx-translate/core' ;
2831import { SortDirection , SortOptions } from '../../../core/cache/models/sort-options.model' ;
2932
3033@Component ( {
3134 selector : 'ds-metadata-field-selector' ,
3235 styleUrls : [ './metadata-field-selector.component.scss' ] ,
33- templateUrl : './metadata-field-selector.component.html'
36+ templateUrl : './metadata-field-selector.component.html' ,
3437} )
3538/**
3639 * Component displaying a searchable input for metadata-fields
@@ -67,7 +70,7 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterV
6770 * List of available metadata field options to choose from, dependent on the current query the user entered
6871 * Shows up in a dropdown below the input
6972 */
70- mdFieldOptions$ : Observable < string [ ] > ;
73+ mdFieldOptions$ : BehaviorSubject < string [ ] > = new BehaviorSubject < string [ ] > ( [ ] ) ;
7174
7275 /**
7376 * FormControl for the input
@@ -102,6 +105,30 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterV
102105 */
103106 subs : Subscription [ ] = [ ] ;
104107
108+
109+ /**
110+ * The current page to load
111+ * Dynamically goes up as the user scrolls down until it reaches the last page possible
112+ */
113+ currentPage$ = new BehaviorSubject ( 1 ) ;
114+
115+ /**
116+ * Whether or not the list contains a next page to load
117+ * This allows us to avoid next pages from trying to load when there are none
118+ */
119+ hasNextPage = false ;
120+
121+ /**
122+ * Whether or not new results are currently loading
123+ */
124+ loading = false ;
125+
126+ /**
127+ * Default page option for this feature
128+ */
129+ pageOptions = { elementsPerPage : 20 , sort : new SortOptions ( 'fieldName' , SortDirection . ASC ) } ;
130+
131+
105132 constructor ( protected registryService : RegistryService ,
106133 protected notificationsService : NotificationsService ,
107134 protected translate : TranslateService ) {
@@ -112,32 +139,33 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterV
112139 * Update the mdFieldOptions$ depending on the query$ fired by querying the server
113140 */
114141 ngOnInit ( ) : void {
142+ this . subs . push ( this . input . valueChanges . pipe (
143+ debounceTime ( this . debounceTime ) ,
144+ startWith ( '' ) ,
145+ ) . subscribe ( ( valueChange ) => {
146+ this . currentPage$ . next ( 1 ) ;
147+ if ( ! this . selectedValueLoading ) {
148+ this . query$ . next ( valueChange ) ;
149+ }
150+ this . mdField = valueChange ;
151+ this . mdFieldChange . emit ( this . mdField ) ;
152+ } ) ) ;
115153 this . subs . push (
116- this . input . valueChanges . pipe (
117- debounceTime ( this . debounceTime ) ,
118- ) . subscribe ( ( valueChange ) => {
119- if ( ! this . selectedValueLoading ) {
120- this . query$ . next ( valueChange ) ;
121- }
122- this . selectedValueLoading = false ;
123- this . mdField = valueChange ;
124- this . mdFieldChange . emit ( this . mdField ) ;
125- } ) ,
126- ) ;
127- this . mdFieldOptions$ = this . query$ . pipe (
128- distinctUntilChanged ( ) ,
129- switchMap ( ( query : string ) => {
130- this . showInvalid = false ;
131- if ( query !== null ) {
132- return this . registryService . queryMetadataFields ( query , { elementsPerPage : 10 , sort : new SortOptions ( 'fieldName' , SortDirection . ASC ) } , true , false , followLink ( 'schema' ) ) . pipe (
133- getAllSucceededRemoteData ( ) ,
134- metadataFieldsToString ( ) ,
135- ) ;
136- } else {
137- return [ [ ] ] ;
138- }
139- } ) ,
140- ) ;
154+ observableCombineLatest (
155+ this . query$ ,
156+ this . currentPage$ ,
157+ )
158+ . pipe (
159+ switchMap ( ( [ query , page ] : [ string , number ] ) => {
160+ this . loading = true ;
161+ if ( page === 1 ) {
162+ this . mdFieldOptions$ . next ( [ ] ) ;
163+ }
164+ return this . search ( query as string , page as number ) ;
165+ } ) ,
166+ ) . subscribe ( ( rd ) => {
167+ if ( ! this . selectedValueLoading ) { this . updateList ( rd ) ; }
168+ } ) ) ;
141169 }
142170
143171 /**
@@ -181,6 +209,41 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterV
181209 this . input . setValue ( mdFieldOption ) ;
182210 }
183211
212+
213+ /**
214+ * When the user reaches the bottom of the page (or almost) and there's a next page available, increase the current page
215+ */
216+ onScrollDown ( ) {
217+ if ( this . hasNextPage && ! this . loading ) {
218+ this . currentPage$ . next ( this . currentPage$ . value + 1 ) ;
219+ }
220+ }
221+
222+ /**
223+ * @Description It update the mdFieldOptions$ according the query result page
224+ * */
225+ updateList ( list : string [ ] ) {
226+ this . loading = false ;
227+ this . hasNextPage = list . length > 0 ;
228+ const currentEntries = this . mdFieldOptions$ . getValue ( ) ;
229+ this . mdFieldOptions$ . next ( [ ...currentEntries , ...list ] ) ;
230+ this . selectedValueLoading = false ;
231+ }
232+ /**
233+ * Perform a search for the current query and page
234+ * @param query Query to search objects for
235+ * @param page Page to retrieve
236+ * @param useCache Whether or not to use the cache
237+ */
238+ search ( query : string , page : number , useCache : boolean = true ) {
239+ return this . registryService . queryMetadataFields ( query , {
240+ elementsPerPage : this . pageOptions . elementsPerPage , sort : this . pageOptions . sort ,
241+ currentPage : page } , useCache , false , followLink ( 'schema' ) )
242+ . pipe (
243+ getAllSucceededRemoteData ( ) ,
244+ metadataFieldsToString ( ) ,
245+ ) ;
246+ }
184247 /**
185248 * Unsubscribe from any open subscriptions
186249 */
0 commit comments