Skip to content

Commit

Permalink
change!: turn item width into visible item count
Browse files Browse the repository at this point in the history
This makes it declarative unlike before when the item count had to be
calculated from the item and viewer width, which not only saves code but
also resources.

One observation of mine is that this relatively simple change required
quite a few changes in the unit tests. It only shows that testing components
in Angular is pain (calling ngOnChanges, calling tick in fakeAsync etc.)
which makes a good argument for cy's component testing.
  • Loading branch information
daelmaak committed Aug 10, 2023
1 parent bc28b3f commit 80cce04
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 123 deletions.
4 changes: 2 additions & 2 deletions apps/demo/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ <h2 id="demos">Demos</h2>
stackblitz="https://stackblitz.com/edit/ngx-gallery-demo-infinite-loop?file=src%2Fapp%2Fapp.component.html"
>
<gallery
[items]="smallerImages"
[items]="images"
[loop]="true"
loading="lazy"
[itemWidth]="mobile ? '75%' : '34%'"
[visibleItems]="mobile ? 1.5 : 3"
></gallery>
</app-showcase>

Expand Down
5 changes: 0 additions & 5 deletions apps/demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,6 @@ export class AppComponent {
},
];

smallerImages = this.images.map(i => ({
...i,
src: i.src.replace('-lg', '-md'),
}));

extendedImages: GalleryItem[] = [
...this.images,
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
<mat-form-field>
<mat-label>Item width</mat-label>
<input
name="itemWidth"
matInput
[(ngModel)]="itemWidth"
(change)="reloadGallery()"
/>
</mat-form-field>

<gallery
*ngIf="showGallery"
[items]="items"
[itemWidth]="itemWidth"
[visibleItems]="mobile ? 1.5 : 2.5"
loading="lazy"
></gallery>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import {
ChangeDetectorRef,
Component,
Input,
OnChanges,
SimpleChanges,
} from '@angular/core';
import { GalleryItem } from '@daelmaak/ngx-gallery';

Expand All @@ -14,21 +12,14 @@ import { GalleryItem } from '@daelmaak/ngx-gallery';
styleUrls: ['./demo-multiple-items.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DemoMultipleItemsComponent implements OnChanges {
export class DemoMultipleItemsComponent {
@Input() items: GalleryItem[];
@Input() mobile: boolean;

itemWidth: string;
showGallery = true;

constructor(private cd: ChangeDetectorRef) {}

ngOnChanges({ mobile }: SimpleChanges) {
if (mobile && mobile.firstChange) {
this.itemWidth = this.mobile ? 'calc(100% / 1.5)' : 'calc(100% / 2.5)';
}
}

reloadGallery() {
this.showGallery = false;
this.cd.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ <h4>Gallery viewer properties</h4>

<section>
<mat-form-field>
<label>Item width</label>
<label>Number of displayed items</label>
<input
name="itemWidth"
name="visibleItems"
matInput
[(ngModel)]="galleryConfig.itemWidth"
[(ngModel)]="galleryConfig.visibleItems"
(change)="reloadGallery()"
/>
</mat-form-field>
Expand Down Expand Up @@ -203,7 +203,7 @@ <h4>Auxiliary</h4>
[touchGestures]="galleryConfig.touchGestures"
[counter]="galleryConfig.counter"
[counterOrientation]="galleryConfig.counterOrientation"
[itemWidth]="galleryConfig.itemWidth"
[visibleItems]="galleryConfig.visibleItems"
[objectFit]="galleryConfig.objectFit"
[loading]="galleryConfig.loading"
[loop]="galleryConfig.loop"
Expand All @@ -215,7 +215,6 @@ <h4>Auxiliary</h4>
[thumbsArrows]="galleryConfig.thumbsArrows"
[thumbsArrowSlideByLength]="galleryConfig.thumbsArrowSlideByLength"
[thumbsScrollBehavior]="galleryConfig.thumbsScrollBehavior"
(imageClick)="onImageClick($event)"
(descriptionClick)="galleryConfig.descriptions = false"
></gallery>
</div>
Expand All @@ -234,12 +233,7 @@ <h4>Auxiliary</h4>
<ng-container *ngIf="item.video; then videoTemplate; else imgTemplate">
</ng-container>
<ng-template #imgTemplate>
<img
#img
class="custom-media"
[src]="seen ? item.src : ''"
(load)="onImageLoad()"
/>
<img #img class="custom-media" [src]="seen ? item.src : ''" />
<div class="custom-loading" *ngIf="seen && img.naturalHeight <= 0">
Custom item loading ...
</div>
Expand All @@ -250,7 +244,6 @@ <h4>Auxiliary</h4>
class="custom-media"
[src]="seen ? item.src : ''"
controls
(loadedmetadata)="onImageLoad()"
></video>
</ng-template>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { delay, switchMap } from 'rxjs/operators';
import {
GalleryComponent,
GalleryItem,
GalleryItemEvent,
Loading,
ObjectFit,
Orientation,
Expand All @@ -26,7 +25,7 @@ interface GalleryConfig {
touchGestures: boolean;
counter: boolean;
counterOrientation: VerticalOrientation;
itemWidth: string;
visibleItems: number;
objectFit: ObjectFit;
loading: Loading;
loop: boolean;
Expand Down Expand Up @@ -62,7 +61,7 @@ export class DemoWholeConfigComponent implements OnInit {
touchGestures: true,
counter: true,
counterOrientation: 'bottom',
itemWidth: '',
visibleItems: 1,
objectFit: 'cover',
loading: 'lazy',
loop: false,
Expand Down Expand Up @@ -92,14 +91,7 @@ export class DemoWholeConfigComponent implements OnInit {
window.addEventListener('pagehide', this.storeGalleryConfig);
}

async onImageClick(event: GalleryItemEvent) {}

onImageLoad() {}

onConfigChange(
prop: keyof GalleryConfig,
value: GalleryConfig[keyof GalleryConfig]
) {
onConfigChange(prop: keyof GalleryConfig, value: unknown) {
if (value === '') {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
[touchGestures]="touchGestures"
[counter]="counter"
[counterOrientation]="counterOrientation"
[itemWidth]="itemWidth"
[visibleItems]="visibleItems"
[objectFit]="objectFit"
[loading]="loading"
[itemTemplate]="itemTemplate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class GalleryComponent {
@Input() touchGestures = true;
@Input() counter = true;
@Input() counterOrientation: VerticalOrientation = 'bottom';
@Input() itemWidth: string;
@Input() visibleItems = 1;
@Input() loading: Loading = 'lazy';
@Input() loop = false;
@Input() objectFit: ObjectFit = 'cover';
Expand Down
4 changes: 2 additions & 2 deletions libs/gallery/src/lib/components/viewer/viewer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
</button>

<ul #itemList [attr.aria-label]="aria?.viewerLabel">
<li *ngIf="!_displayedItems?.length" class="viewer-initial-item"></li>
<li *ngIf="!displayedItems?.length" class="viewer-initial-item"></li>
<li
#itemsRef
*ngFor="let item of _displayedItems; let i = index"
*ngFor="let item of displayedItems; let i = index"
media
[class.viewer-item--selected]="i === selectedIndex"
[attr.tabindex]="itemTabbable(i)"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectorRef } from '@angular/core';
import { ChangeDetectorRef, SimpleChange } from '@angular/core';
import { GalleryItemInternal } from '../../core/gallery-item';
import { ViewerComponent } from './viewer.component';

Expand Down Expand Up @@ -26,32 +26,24 @@ describe('ViewerComponent', () => {
{ src: 'src3' },
{ src: 'src4' },
];
viewer['_viewerWidth'] = 600;
});

it('should be 1 when just 1 item visible in the viewport', () => {
viewer['_itemWidth'] = 600;
const fringeCount = viewer['getFringeCount']();

expect(fringeCount).toBe(1);
});

it('should be 1 when 1 item is visible but is by a fraction of a pixel slimmer than the scrollport', () => {
viewer['_itemWidth'] = 599.5;
viewer.visibleItems = 1;
const fringeCount = viewer['getFringeCount']();

expect(fringeCount).toBe(1);
});

it('should be 2 when gallery item is a little slimmer than scrollport', () => {
viewer['_itemWidth'] = 550;
viewer.visibleItems = 1.2;
const fringeCount = viewer['getFringeCount']();

expect(fringeCount).toBe(2);
});

it('should be 3 when 3 items visible', () => {
viewer['_itemWidth'] = 200;
viewer.visibleItems = 3;
const fringeCount = viewer['getFringeCount']();

expect(fringeCount).toBe(3);
Expand Down Expand Up @@ -123,15 +115,4 @@ describe('ViewerComponent', () => {
});
});
});

describe('looping', () => {
beforeEach(() => {
viewer.loop = true;
viewer.items = [{ src: 'src1' }];
});

it('should disabled looping if there is just 1 item', () => {
expect(viewer.loop).toBe(false);
});
});
});
46 changes: 38 additions & 8 deletions libs/gallery/src/lib/components/viewer/viewer.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
Component,
DebugElement,
SimpleChange,
SimpleChanges,
TemplateRef,
ViewChild,
} from '@angular/core';
Expand Down Expand Up @@ -83,10 +82,12 @@ describe('ViewerComponent', () => {
}));

it('should preselect item based on given index', fakeAsync(() => {
component.visibleItems = 1;
component.selectedIndex = 1;
component.items = [{ src: 'src1' }, { src: 'src2' }];
const changes = {
items: new SimpleChange(null, component.items, true),
visibleItems: new SimpleChange(undefined, component.visibleItems, true),
items: new SimpleChange(undefined, component.items, true),
};
component.ngOnChanges(changes);
fixture.detectChanges();
Expand All @@ -95,6 +96,21 @@ describe('ViewerComponent', () => {

expect(getSlidePx().index).toBe(-1);
}));

it('looping should be disabled if there is just 1 item', fakeAsync(() => {
component.loop = true;
component.items = [{ src: 'src1' }];
component.visibleItems = 1;
const changes = {
items: new SimpleChange(null, component.items, true),
};
component.ngOnChanges(changes);
fixture.detectChanges();
tick();

expect(component.loop).toBe(false);
expect(component.displayedItems.length).toBe(1);
}));
});

describe('class attribute', () => {
Expand Down Expand Up @@ -245,8 +261,6 @@ describe('ViewerComponent', () => {

describe('with looping on', () => {
beforeEach(() => {
spyOn(component, 'shift' as any);
spyOn(component, 'center' as any);
component.loop = true;
fixture.detectChanges();
});
Expand Down Expand Up @@ -313,12 +327,18 @@ describe('ViewerComponent', () => {
component.mouseGestures = true;
component.touchGestures = true;
component.selectedIndex = 0;
component.visibleItems = 1;
});

describe('in loop mode with 2 (1 on each side) fringe items', () => {
beforeEach(fakeAsync(() => {
component.loop = true;
component.ngOnChanges({
visibleItems: new SimpleChange(
undefined,
component.visibleItems,
true
),
items: new SimpleChange(null, component.items, true),
});
fixture.detectChanges();
Expand Down Expand Up @@ -413,9 +433,15 @@ describe('ViewerComponent', () => {

describe('with looping off', () => {
beforeEach(fakeAsync(() => {
component.visibleItems = 1;
component.loop = false;
component.ngOnChanges({
items: new SimpleChange(null, component.items, true),
visibleItems: new SimpleChange(
undefined,
component.visibleItems,
true
),
items: new SimpleChange(undefined, component.items, true),
});
fixture.detectChanges();
viewerDe.nativeElement.style.width = ITEM_WIDTH + 'px';
Expand Down Expand Up @@ -531,9 +557,15 @@ describe('ViewerComponent', () => {

describe('in right to left mode', () => {
beforeEach(fakeAsync(() => {
component.visibleItems = 1;
component.loop = false;
component.isRtl = true;
component.ngOnChanges({
visibleItems: new SimpleChange(
undefined,
component.visibleItems,
true
),
items: new SimpleChange(null, component.items, true),
});
fixture.detectChanges();
Expand Down Expand Up @@ -587,9 +619,7 @@ describe('ViewerComponent', () => {
};
}

const [_, index, tweak] = transform.match(
/3d\(calc\((\-?\d+).*\s(\d+)px\)/
);
const [, index, tweak] = transform.match(/3d\(calc\((-?\d+).*\s(\d+)px\)/);

return {
index: +index,
Expand Down
Loading

0 comments on commit 80cce04

Please sign in to comment.