Skip to content

Commit

Permalink
fix(datepicker): schedule positioning calculations correctly
Browse files Browse the repository at this point in the history
Popper is now created outside Angular and updates are scheduled only after datepicker is shown.
  • Loading branch information
maxokorokov committed May 17, 2022
1 parent 077047e commit 745a64d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
22 changes: 22 additions & 0 deletions src/datepicker/datepicker-input.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {TestBed, ComponentFixture, fakeAsync, tick, waitForAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {createGenericTestComponent} from '../test/common';
import createSpy = jasmine.createSpy;

import {Component, Injectable} from '@angular/core';
import {FormsModule, NgForm} from '@angular/forms';
Expand Down Expand Up @@ -125,6 +126,26 @@ describe('NgbInputDatepicker', () => {

it('should support the "position" option',
() => { createTestCmpt(`<input ngbDatepicker #d="ngbDatepicker" [placement]="'bottom-right'">`); });

it('should cleanup datepicker when parent container is destroyed', () => {
const fixture = createTestCmpt(`
<ng-template [ngIf]="show">
<input ngbDatepicker #d="ngbDatepicker">
</ng-template>`);
const datepicker = fixture.debugElement.query(By.directive(NgbInputDatepicker)).injector.get(NgbInputDatepicker);

datepicker.open();
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('ngb-datepicker')).not.toBeNull();

const closedSpy = createSpy();
datepicker.closed.subscribe(closedSpy);

fixture.componentInstance.show = false;
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('ngb-datepicker')).toBeNull();
expect(closedSpy).toHaveBeenCalledTimes(1);
});
});

describe('ngModel interactions', () => {
Expand Down Expand Up @@ -1157,6 +1178,7 @@ class TestComponent {
maxDate: NgbDateStruct;
isDisabled;
popupClass = 'my-datepicker-popup';
show = true;

onNavigate(params) {}

Expand Down
16 changes: 7 additions & 9 deletions src/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {NgbDateStruct} from './ngb-date-struct';
import {NgbInputDatepickerConfig} from './datepicker-input-config';
import {NgbDatepickerConfig} from './datepicker-config';
import {isString} from '../util/util';
import {take} from 'rxjs/operators';
import {Subject} from 'rxjs';
import {addPopperOffset} from '../util/positioning-util';

Expand Down Expand Up @@ -290,7 +289,6 @@ export class NgbInputDatepicker implements OnChanges,
@Inject(DOCUMENT) private _document: any, private _changeDetector: ChangeDetectorRef,
config: NgbInputDatepickerConfig) {
['autoClose', 'container', 'positionTarget', 'placement'].forEach(input => this[input] = config[input]);
this._zoneSubscription = _ngZone.onStable.subscribe(() => this._positioning.update());
}

registerOnChange(fn: (value: any) => any): void { this._onChange = fn; }
Expand Down Expand Up @@ -388,7 +386,8 @@ export class NgbInputDatepicker implements OnChanges,
hostElement = this._elRef.nativeElement;
}

this._ngZone.onStable.pipe(take(1)).subscribe(() => {
// Setting up popper and scheduling updates when zone is stable
this._ngZone.runOutsideAngular(() => {
if (this._cRef) {
this._positioning.createPopper({
hostElement,
Expand All @@ -397,6 +396,8 @@ export class NgbInputDatepicker implements OnChanges,
appendToBody: this.container === 'body',
updatePopperOptions: addPopperOffset([0, 2])
});

this._zoneSubscription = this._ngZone.onStable.subscribe(() => this._positioning.update());
}
});

Expand All @@ -415,6 +416,8 @@ export class NgbInputDatepicker implements OnChanges,
if (this.isOpen()) {
this._vcRef.remove(this._vcRef.indexOf(this._cRef !.hostView));
this._cRef = null;
this._positioning.destroy();
this._zoneSubscription ?.unsubscribe();
this._destroyCloseHandlers$.next();
this.closed.emit();
this._changeDetector.markForCheck();
Expand All @@ -433,8 +436,6 @@ export class NgbInputDatepicker implements OnChanges,
} else {
this._document.body.focus();
}

this._positioning.destroy();
}
}

Expand Down Expand Up @@ -492,10 +493,7 @@ export class NgbInputDatepicker implements OnChanges,
}
}

ngOnDestroy() {
this.close();
this._zoneSubscription.unsubscribe();
}
ngOnDestroy() { this.close(); }

private _applyDatepickerInputs(datepickerInstance: NgbDatepicker): void {
['dayTemplate', 'dayTemplateData', 'displayMonths', 'firstDayOfWeek', 'footerTemplate', 'markDisabled', 'minDate',
Expand Down

0 comments on commit 745a64d

Please sign in to comment.