From b0525c62ab2fc4a66a0a18804f944610b00c2b44 Mon Sep 17 00:00:00 2001 From: Murhaf Sousli Date: Sat, 24 Aug 2024 06:19:53 +0200 Subject: [PATCH] Update --- CHANGELOG.md | 2 +- .../src/app/app.component.html | 4 +- .../src/app/home/lab/lab.component.html | 31 +++++----- .../src/app/home/lab/lab.component.ts | 9 ++- .../http/src/ng-progress-http.directive.ts | 2 +- projects/ngx-progressbar/package.json | 2 +- .../src/lib/ng-progress-ref.ts | 59 ++++++++++++++----- .../src/lib/tests/ng-progress-http.spec.ts | 8 +-- .../src/lib/tests/ng-progress-ref.spec.ts | 23 +++++++- 9 files changed, 91 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f8eff..2fd79de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 12.0.0 +## 12.0.1 - Upgrade to Angular 18 (still compatible v17.3.0 and above). - feat: Introduce CSS variables for more flexible customization, see [styling](https://github.com/MurhafSousli/ngx-progressbar/wiki/styling). diff --git a/projects/ngx-progressbar-demo/src/app/app.component.html b/projects/ngx-progressbar-demo/src/app/app.component.html index 77cf14e..f3b8d28 100644 --- a/projects/ngx-progressbar-demo/src/app/app.component.html +++ b/projects/ngx-progressbar-demo/src/app/app.component.html @@ -1,6 +1,6 @@
- +
- +
diff --git a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.html b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.html index fc54f03..1ca9b2f 100644 --- a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.html +++ b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.html @@ -6,7 +6,9 @@ direction = @@ -16,11 +18,13 @@ - trickleSpeed = + trickleSpeed = - debounceTime = + debounceTime = @@ -40,18 +44,13 @@ spinnerPosition = - - - - - - - relative = @@ -60,17 +59,15 @@ - min = + min = - max = + max = - - - - started = onStarted() diff --git a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts index 301f261..df4e32e 100644 --- a/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts +++ b/projects/ngx-progressbar-demo/src/app/home/lab/lab.component.ts @@ -1,5 +1,4 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { NgProgressOptions } from 'ngx-progressbar'; @@ -9,23 +8,23 @@ import { NgProgressOptions } from 'ngx-progressbar'; templateUrl: './lab.component.html', styleUrls: ['./lab.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - imports: [FormsModule, CommonModule] + imports: [FormsModule] }) export class LabComponent { - directions = [ + directions: string[] = [ 'ltr+', 'ltr-', 'rtl+', 'rtl-' ]; - spinnerPosition = [ + spinnerPosition: string[] = [ 'right', 'left' ]; @Input() options: NgProgressOptions = {}; - @Output() optionsChange = new EventEmitter(true); + @Output() optionsChange: EventEmitter = new EventEmitter(true); } diff --git a/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts b/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts index a461772..085d729 100644 --- a/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts +++ b/projects/ngx-progressbar/http/src/ng-progress-http.directive.ts @@ -13,7 +13,7 @@ class NgProgressHttpBase { effect(() => { if (this.manager.requestsLoading()) { this.progressRef.start(); - } else { + } else if (this.progressRef.isActive) { this.progressRef.complete(); } }, { allowSignalWrites: true }); diff --git a/projects/ngx-progressbar/package.json b/projects/ngx-progressbar/package.json index ae57d13..4f28992 100644 --- a/projects/ngx-progressbar/package.json +++ b/projects/ngx-progressbar/package.json @@ -1,6 +1,6 @@ { "name": "ngx-progressbar", - "version": "12.0.0", + "version": "12.0.1", "author": { "name": "Murhaf Sousli", "url": "https://github.com/MurhafSousli", diff --git a/projects/ngx-progressbar/src/lib/ng-progress-ref.ts b/projects/ngx-progressbar/src/lib/ng-progress-ref.ts index 3249668..965c8fd 100644 --- a/projects/ngx-progressbar/src/lib/ng-progress-ref.ts +++ b/projects/ngx-progressbar/src/lib/ng-progress-ref.ts @@ -1,8 +1,19 @@ -import { inject, signal, effect, computed, Directive, OnDestroy, Signal, WritableSignal, EffectCleanupRegisterFn } from '@angular/core'; +import { + inject, + signal, + effect, + computed, + Directive, + OnDestroy, + Signal, + WritableSignal, + EffectCleanupRegisterFn +} from '@angular/core'; import { Observable, Subject, Subscription, + BehaviorSubject, of, tap, delay, @@ -14,6 +25,11 @@ import { } from 'rxjs'; import { NgProgressOptions, NG_PROGRESS_OPTIONS } from './ng-progress.model'; +enum TriggerType { + START = 'START', + COMPLETE = 'COMPLETE' +} + @Directive({ standalone: true, selector: '[ngProgressRef]', @@ -27,15 +43,21 @@ export class NgProgressRef implements OnDestroy { private _active: WritableSignal = signal(false); - active: Signal = computed(() => this._active()); + // A boolean flag that indicates the active state + isActive: boolean; + + active: Signal = computed(() => { + this.isActive = this._active(); + return this.isActive; + }); progress: Signal = computed(() => this._progress()); config: Signal = computed(() => this._config()); - private readonly _trigger: WritableSignal = signal(false); + private _trigger: BehaviorSubject = new BehaviorSubject(null); - // Progress start source event (used to cancel finalizing delays) + // Progress start source event (used to cancel onComplete delays) private readonly _started: Subject = new Subject(); readonly started: Observable = this._started.asObservable(); @@ -54,20 +76,23 @@ export class NgProgressRef implements OnDestroy { effect((onCleanup: EffectCleanupRegisterFn) => { sub$?.unsubscribe(); - if (this._trigger()) { - sub$ = timer(this.config().debounceTime).pipe( - switchMap(() => this.onTrickling(this.config())) - ).subscribe(); - } else { - setTimeout(() => { - sub$ = this.onComplete(this.config()).subscribe(); - }); - } + sub$ = this._trigger.pipe( + switchMap((trigger: TriggerType) => { + if (trigger === TriggerType.START) { + return timer(this.config().debounceTime).pipe( + switchMap(() => this.onTrickling(this.config())) + ); + } else if (trigger === TriggerType.COMPLETE) { + return this.onComplete(this.config()); + } + return EMPTY; + }) + ).subscribe(); onCleanup(() => { sub$?.unsubscribe(); }); - }); + }, { allowSignalWrites: true }); } ngOnDestroy(): void { @@ -80,7 +105,7 @@ export class NgProgressRef implements OnDestroy { */ start(): void { this._started.next(); - this._trigger.set(true); + this._trigger.next(TriggerType.START); this._active.set(true); } @@ -88,7 +113,7 @@ export class NgProgressRef implements OnDestroy { * Complete the progress */ complete(): void { - this._trigger.set(false); + this._trigger.next(TriggerType.COMPLETE); } /** @@ -110,6 +135,8 @@ export class NgProgressRef implements OnDestroy { * Set the progress */ set(n: number): void { + // this._trigger.set(TriggerType.SET); + this._active.set(true); this._progress.set(this.clamp(n)); } diff --git a/projects/ngx-progressbar/src/lib/tests/ng-progress-http.spec.ts b/projects/ngx-progressbar/src/lib/tests/ng-progress-http.spec.ts index 63dd53d..b52aea6 100644 --- a/projects/ngx-progressbar/src/lib/tests/ng-progress-http.spec.ts +++ b/projects/ngx-progressbar/src/lib/tests/ng-progress-http.spec.ts @@ -40,18 +40,18 @@ describe(`NgProgressHttp`, () => { httpClient = TestBed.inject(HttpClient); httpTestingController = TestBed.inject(HttpTestingController); - const startSpy: jasmine.Spy = spyOn(progressRef, 'start'); + const startSpy: jasmine.Spy = spyOn(progressRef, 'start').and.callThrough(); const completeSpy: jasmine.Spy = spyOn(progressRef, 'complete'); httpClient.get('/users').subscribe(() => { - // Check that progress.complete() has been called after the request is completed - // Need to check that async setTimeout(() => { + // Check that progress.complete() has been called after the request is completed expect(completeSpy).toHaveBeenCalled(); done(); }); }); + // Need to detect changes fixture.detectChanges(); // Check that progress.start() has been called @@ -60,7 +60,7 @@ describe(`NgProgressHttp`, () => { const req: TestRequest = httpTestingController.expectOne('/users'); expect(req.request.method).toEqual('GET'); - // Complete the request after a tiny delay + // Complete the request after 200ms delay setTimeout(() => { req.flush({}); }, 200); diff --git a/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts b/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts index 2ab02be..b6df79d 100644 --- a/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts +++ b/projects/ngx-progressbar/src/lib/tests/ng-progress-ref.spec.ts @@ -46,7 +46,7 @@ describe('NgProgressRef', () => { expect(directive.active()).toBeFalse(); }); - it('should start and complete the progress', (done: DoneFn) => { + it('should call continuously call set() on trickling', (done: DoneFn) => { const setSpy: jasmine.Spy = spyOn(directive, 'set'); // Assume active state is off directive['_active'].set(false); @@ -57,6 +57,18 @@ describe('NgProgressRef', () => { }); }); + it('should set the progress even if it has not started', async () => { + // Assume active state is off + directive.set(40); + fixture.detectChanges(); + expect(directive.progress()).toBe(40); + expect(directive.active()).toBeTrue(); + + directive.complete(); + fixture.detectChanges(); + await afterTimeout(350); + expect(directive.active()).toBeFalse(); + }); it('should increment the progress when inc function is called', async () => { directive.inc(); @@ -94,13 +106,20 @@ describe('NgProgressRef', () => { directive.setConfig(newConfig); expect(directive.config()).toEqual(newConfig); }); + + it('should not do anything if complete() is called when progress has not started', () => { + const completeSpy: jasmine.Spy = spyOn(directive, 'complete').and.callThrough(); + directive.complete(); + fixture.detectChanges(); + expect(completeSpy).toHaveBeenCalled(); + }); }); @Component({ standalone: true, imports: [NgProgressRef], template: ` -
+
` }) class TestComponent {