mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[DURACOM-304] Refactored scripts-select.component by using infinite scroll instead of page size 9999
This commit is contained in:

committed by
FrancescoMolinaro

parent
4536d9c74d
commit
2b58377830
@@ -1,20 +1,46 @@
|
|||||||
<div class="form-group" *ngIf="scripts$ | async">
|
<div class="d-flex w-100 flex-column gap-3">
|
||||||
<label for="process-script">{{'process.new.select-script' | translate}}</label>
|
<div>
|
||||||
<select required id="process-script"
|
<div ngbDropdown class="d-flex">
|
||||||
class="form-control"
|
<input id="process-script"
|
||||||
name="script"
|
class="form-control"
|
||||||
[(ngModel)]="selectedScript"
|
required
|
||||||
#script="ngModel">
|
[ngModel]="selectedScript"
|
||||||
<option [ngValue]="undefined">{{'process.new.select-script.placeholder' | translate}}</option>
|
placeholder="{{'process.new.select-script.placeholder' | translate}}"
|
||||||
<option *ngFor="let script of scripts$ | async" [ngValue]="script.id">
|
[ngModelOptions]="{standalone: true}"
|
||||||
{{script.name}}
|
ngbDropdownToggle
|
||||||
</option>
|
#script="ngModel">
|
||||||
</select>
|
<div ngbDropdownMenu aria-labelledby="process-script" class="w-100 scrollable-menu"
|
||||||
|
role="menu"
|
||||||
|
(scroll)="onScroll($event)"
|
||||||
|
infiniteScroll
|
||||||
|
[infiniteScrollDistance]="5"
|
||||||
|
[infiniteScrollThrottle]="300"
|
||||||
|
[infiniteScrollUpDistance]="1.5"
|
||||||
|
[fromRoot]="true"
|
||||||
|
[scrollWindow]="false">
|
||||||
|
<button class="dropdown-item"
|
||||||
|
*ngFor="let script of scripts"
|
||||||
|
role="menuitem"
|
||||||
|
type="button"
|
||||||
|
title="{{ script.name }}"
|
||||||
|
(click)="onSelect(script);">
|
||||||
|
<span class="text-truncate">{{ script.name }}</span>
|
||||||
|
</button>
|
||||||
|
<ng-container *ngIf="(isLoading$ | async)">
|
||||||
|
<button class="dropdown-item disabled" role="menuitem">
|
||||||
|
<ds-loading message="{{'loading.default' | translate}}">
|
||||||
|
</ds-loading>
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div *ngIf="script.invalid && (script.dirty || script.touched)"
|
<div *ngIf="script.invalid && (script.dirty || script.touched)"
|
||||||
class="alert alert-danger validation-error">
|
class="alert alert-danger validation-error">
|
||||||
<div *ngIf="script.errors.required">
|
<div *ngIf="script.errors.required">
|
||||||
{{'process.new.select-script.required' | translate}}
|
{{ 'process.new.select-script.required' | translate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
.dropdown-item {
|
||||||
|
padding: 0.35rem 1rem;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-menu {
|
||||||
|
height: auto;
|
||||||
|
max-height: var(--ds-dropdown-menu-max-height);
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:not(:last-of-type) .dropdown-item {
|
||||||
|
border-bottom: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#entityControlsDropdownMenu {
|
||||||
|
outline: 0;
|
||||||
|
left: 0 !important;
|
||||||
|
box-shadow: var(--bs-btn-focus-box-shadow);
|
||||||
|
}
|
||||||
|
@@ -1,14 +1,19 @@
|
|||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Optional, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Optional, Output } from '@angular/core';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
import { Script } from '../../scripts/script.model';
|
import { Script } from '../../scripts/script.model';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { BehaviorSubject, Observable, Subscription, tap } from 'rxjs';
|
||||||
import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators';
|
||||||
import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../../core/shared/operators';
|
import {
|
||||||
|
getRemoteDataPayload,
|
||||||
|
getFirstSucceededRemoteData,
|
||||||
|
getFirstCompletedRemoteData
|
||||||
|
} from '../../../core/shared/operators';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { hasNoValue, hasValue } from '../../../shared/empty.util';
|
import { hasNoValue, hasValue } from '../../../shared/empty.util';
|
||||||
import { ControlContainer, NgForm } from '@angular/forms';
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
import { controlContainerFactory } from '../process-form.component';
|
import { controlContainerFactory } from '../process-form.component';
|
||||||
|
import { FindListOptions } from "../../../core/data/find-list-options.model";
|
||||||
|
|
||||||
const SCRIPT_QUERY_PARAMETER = 'script';
|
const SCRIPT_QUERY_PARAMETER = 'script';
|
||||||
|
|
||||||
@@ -31,10 +36,20 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* All available scripts
|
* All available scripts
|
||||||
*/
|
*/
|
||||||
scripts$: Observable<Script[]>;
|
scripts: Script[] = [];
|
||||||
|
|
||||||
private _selectedScript: Script;
|
private _selectedScript: Script;
|
||||||
private routeSub: Subscription;
|
private routeSub: Subscription;
|
||||||
|
|
||||||
|
private _isLastPage = false;
|
||||||
|
|
||||||
|
scriptOptions: FindListOptions = {
|
||||||
|
elementsPerPage: 20,
|
||||||
|
currentPage: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private scriptService: ScriptDataService,
|
private scriptService: ScriptDataService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -47,31 +62,46 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
|
|||||||
* Checks if the route contains a script ID and auto selects this scripts
|
* Checks if the route contains a script ID and auto selects this scripts
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.scripts$ = this.scriptService.findAll({ elementsPerPage: 9999 })
|
this.loadScripts();
|
||||||
.pipe(
|
}
|
||||||
getFirstSucceededRemoteData(),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
map((paginatedList: PaginatedList<Script>) => paginatedList.page)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.routeSub = this.route.queryParams
|
/**
|
||||||
.pipe(
|
* Load the scripts and check if the route contains a script
|
||||||
filter((params: Params) => hasNoValue(params.id)),
|
*/
|
||||||
map((params: Params) => params[SCRIPT_QUERY_PARAMETER]),
|
loadScripts() {
|
||||||
distinctUntilChanged(),
|
if (this.isLoading$.value) return;
|
||||||
switchMap((id: string) =>
|
this.isLoading$.next(true);
|
||||||
this.scripts$
|
|
||||||
.pipe(
|
this.routeSub = this.scriptService.findAll(this.scriptOptions).pipe(
|
||||||
take(1),
|
getFirstCompletedRemoteData(),
|
||||||
map((scripts) =>
|
getRemoteDataPayload(),
|
||||||
scripts.find((script) => script.id === id)
|
tap((paginatedList: PaginatedList<Script>) => {
|
||||||
)
|
this._isLastPage = paginatedList?.pageInfo?.currentPage >= paginatedList?.pageInfo?.totalPages;
|
||||||
)
|
}),
|
||||||
)
|
map((paginatedList: PaginatedList<Script>) => paginatedList.page),
|
||||||
).subscribe((script: Script) => {
|
).subscribe((newScripts: Script[]) => {
|
||||||
this._selectedScript = script;
|
this.scripts = [...this.scripts, ...newScripts];
|
||||||
this.select.emit(script);
|
this.isLoading$.next(false);
|
||||||
});
|
|
||||||
|
const param = this.route.snapshot.queryParams[SCRIPT_QUERY_PARAMETER];
|
||||||
|
if (hasValue(param)) {
|
||||||
|
this._selectedScript = this.scripts.find((script) => script.id === param);
|
||||||
|
this.select.emit(this._selectedScript);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load more scripts when the user scrolls to the bottom of the list
|
||||||
|
* @param event The scroll event
|
||||||
|
*/
|
||||||
|
onScroll(event: any) {
|
||||||
|
if (event.target.scrollTop + event.target.clientHeight >= event.target.scrollHeight) {
|
||||||
|
if (!this.isLoading$.value && !this._isLastPage) {
|
||||||
|
this.scriptOptions.currentPage++;
|
||||||
|
this.loadScripts();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,6 +123,17 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectScript(script: Script) {
|
||||||
|
this._selectedScript = script;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect(newScript: Script) {
|
||||||
|
this.selectScript(newScript);
|
||||||
|
// this._selectedScript = newScript;
|
||||||
|
this.select.emit(newScript);
|
||||||
|
this.selectedScript = newScript.name;
|
||||||
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set script(value: Script) {
|
set script(value: Script) {
|
||||||
this._selectedScript = value;
|
this._selectedScript = value;
|
||||||
|
Reference in New Issue
Block a user