Skip to content

Commit 59197cf

Browse files
108555: Refactored ItemSelectComponent to not call canSelect every time changes are detected
1 parent da31c4f commit 59197cf

5 files changed

Lines changed: 62 additions & 39 deletions

File tree

src/app/shared/object-select/item-select/item-select.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@
1717
</tr>
1818
</thead>
1919
<tbody>
20-
<tr *ngFor="let item of itemsRD?.payload?.page">
21-
<td><input [disabled]="!(canSelect(item) | async)" class="item-checkbox" [ngModel]="getSelected(item.id) | async" (change)="switch(item.id)" type="checkbox" name="{{item.id}}"></td>
20+
<tr *ngFor="let selectItem of selectItems$ | async">
21+
<td><input [disabled]="(selectItem.canSelect$ | async) === false" class="item-checkbox" [ngModel]="selectItem.selected$ | async" (change)="switch(selectItem.dso.id)" type="checkbox" name="{{selectItem.dso.id}}"></td>
2222
<td *ngIf="!hideCollection">
23-
<span *ngVar="(item.owningCollection | async)?.payload as collection">
23+
<span *ngVar="(selectItem.dso.owningCollection | async)?.payload as collection">
2424
<a *ngIf="collection" [routerLink]="['/collections', collection?.id]">
2525
{{ dsoNameService.getName(collection) }}
2626
</a>
2727
</span>
2828
</td>
29-
<td><span *ngIf="item.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])">{{item.firstMetadataValue(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])}}</span></td>
30-
<td><a [routerLink]="[(itemPageRoutes$ | async)[item.id]]">{{ dsoNameService.getName(item) }}</a></td>
29+
<td><span *ngIf="selectItem.dso.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])">{{selectItem.dso.firstMetadataValue(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])}}</span></td>
30+
<td><a [routerLink]="selectItem.route">{{ dsoNameService.getName(selectItem.dso) }}</a></td>
3131
</tr>
3232
</tbody>
3333
</table>

src/app/shared/object-select/item-select/item-select.component.spec.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,16 @@ describe('ItemSelectComponent', () => {
184184
beforeEach(() => {
185185
comp.featureId = FeatureID.CanManageMappings;
186186
spyOn(authorizationDataService, 'isAuthorized').and.returnValue(of(false));
187+
comp.ngOnInit();
187188
});
188189

189-
it('should disable the checkbox', waitForAsync(() => {
190+
it('should disable the checkbox', waitForAsync(async () => {
190191
fixture.detectChanges();
191-
fixture.whenStable().then(() => {
192-
const checkbox = fixture.debugElement.query(By.css('input.item-checkbox')).nativeElement;
193-
expect(authorizationDataService.isAuthorized).toHaveBeenCalled();
194-
expect(checkbox.disabled).toBeTrue();
195-
});
192+
await fixture.whenStable();
193+
194+
const checkbox = fixture.debugElement.query(By.css('input.item-checkbox')).nativeElement;
195+
expect(authorizationDataService.isAuthorized).toHaveBeenCalled();
196+
expect(checkbox.disabled).toBeTrue();
196197
}));
197198
});
198199
});

src/app/shared/object-select/item-select/item-select.component.ts

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { Component, Input } from '@angular/core';
1+
import { Component, Input, OnInit } from '@angular/core';
22
import { Item } from '../../../core/shared/item.model';
3-
import { ObjectSelectService } from '../object-select.service';
43
import { ObjectSelectComponent } from '../object-select/object-select.component';
54
import { hasValueOperator, isNotEmpty } from '../../empty.util';
65
import { Observable } from 'rxjs';
76
import { getAllSucceededRemoteDataPayload } from '../../../core/shared/operators';
87
import { map } from 'rxjs/operators';
98
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
10-
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
11-
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
9+
import { PaginatedList } from '../../../core/data/paginated-list.model';
10+
import { DSpaceObjectSelect } from '../object-select.model';
1211

1312
@Component({
1413
selector: 'ds-item-select',
@@ -18,7 +17,7 @@ import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
1817
/**
1918
* A component used to select items from a specific list and returning the UUIDs of the selected items
2019
*/
21-
export class ItemSelectComponent extends ObjectSelectComponent<Item> {
20+
export class ItemSelectComponent extends ObjectSelectComponent<Item> implements OnInit {
2221

2322
/**
2423
* Whether or not to hide the collection column
@@ -27,35 +26,25 @@ export class ItemSelectComponent extends ObjectSelectComponent<Item> {
2726
hideCollection = false;
2827

2928
/**
30-
* The routes to the items their pages
31-
* Key: Item ID
32-
* Value: Route to item page
29+
* Collection of all the data that is used to display the {@link Item} in the HTML.
30+
* By collecting this data here it doesn't need to be recalculated on evey change detection.
3331
*/
34-
itemPageRoutes$: Observable<{
35-
[itemId: string]: string
36-
}>;
37-
38-
constructor(
39-
protected objectSelectService: ObjectSelectService,
40-
protected authorizationService: AuthorizationDataService,
41-
public dsoNameService: DSONameService,
42-
) {
43-
super(objectSelectService, authorizationService);
44-
}
32+
selectItems$: Observable<DSpaceObjectSelect<Item>[]>;
4533

4634
ngOnInit(): void {
4735
super.ngOnInit();
4836
if (!isNotEmpty(this.confirmButton)) {
4937
this.confirmButton = 'item.select.confirm';
5038
}
51-
this.itemPageRoutes$ = this.dsoRD$.pipe(
39+
this.selectItems$ = this.dsoRD$.pipe(
5240
hasValueOperator(),
5341
getAllSucceededRemoteDataPayload(),
54-
map((items) => {
55-
const itemPageRoutes = {};
56-
items.page.forEach((item) => itemPageRoutes[item.uuid] = getItemPageRoute(item));
57-
return itemPageRoutes;
58-
})
42+
map((items: PaginatedList<Item>) => items.page.map((item: Item) => Object.assign(new DSpaceObjectSelect<Item>(), {
43+
dso: item,
44+
canSelect$: this.canSelect(item),
45+
selected$: this.getSelected(item.id),
46+
route: getItemPageRoute(item),
47+
} as DSpaceObjectSelect<Item>))),
5948
);
6049
}
6150

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Observable } from 'rxjs';
2+
import { DSpaceObject } from '../../core/shared/dspace-object.model';
3+
4+
/**
5+
* Class used to collect all the data that that is used by the {@link ObjectSelectComponent} in the HTML.
6+
*/
7+
export class DSpaceObjectSelect<T extends DSpaceObject> {
8+
9+
/**
10+
* The {@link DSpaceObject} to display
11+
*/
12+
dso: T;
13+
14+
/**
15+
* Whether the {@link DSpaceObject} can be selected
16+
*/
17+
canSelect$: Observable<boolean>;
18+
19+
/**
20+
* Whether the {@link DSpaceObject} is selected
21+
*/
22+
selected$: Observable<boolean>;
23+
24+
/**
25+
* The {@link DSpaceObject}'s route
26+
*/
27+
route: string;
28+
29+
}

src/app/shared/object-select/object-select/object-select.component.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { SortOptions } from '../../../core/cache/models/sort-options.model';
99
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
1010
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
1111
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
12+
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
1213

1314
/**
1415
* An abstract component used to select DSpaceObjects from a specific list and returning the UUIDs of the selected DSpaceObjects
@@ -17,7 +18,7 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model';
1718
selector: 'ds-object-select-abstract',
1819
template: ''
1920
})
20-
export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestroy {
21+
export abstract class ObjectSelectComponent<TDomain extends DSpaceObject> implements OnInit, OnDestroy {
2122

2223
/**
2324
* A unique key used for the object select service
@@ -88,8 +89,11 @@ export abstract class ObjectSelectComponent<TDomain> implements OnInit, OnDestro
8889
*/
8990
selectedIds$: Observable<string[]>;
9091

91-
constructor(protected objectSelectService: ObjectSelectService,
92-
protected authorizationService: AuthorizationDataService) {
92+
constructor(
93+
protected objectSelectService: ObjectSelectService,
94+
protected authorizationService: AuthorizationDataService,
95+
public dsoNameService: DSONameService,
96+
) {
9397
}
9498

9599
ngOnInit(): void {

0 commit comments

Comments
 (0)