Skip to content

Commit 9c54ba9

Browse files
committed
refactor(modal): prevent body scroll when the modal is visible
1 parent 3734a2a commit 9c54ba9

File tree

1 file changed

+25
-32
lines changed

1 file changed

+25
-32
lines changed

projects/coreui-angular/src/lib/modal/modal/modal.component.ts

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { ModalContentComponent } from '../modal-content/modal-content.component'
3737
display: 'none'
3838
})
3939
),
40-
transition('visible <=> *', [animate('300ms')],)
40+
transition('visible <=> *', [animate('300ms')])
4141
])
4242
],
4343
templateUrl: './modal.component.html',
@@ -50,7 +50,7 @@ export class ModalComponent implements OnInit, OnDestroy {
5050
static ngAcceptInputType_visible: BooleanInput;
5151

5252
constructor(
53-
@Inject(DOCUMENT) private document: any,
53+
@Inject(DOCUMENT) private document: Document,
5454
private renderer: Renderer2,
5555
private hostElement: ElementRef,
5656
private modalService: ModalService,
@@ -111,9 +111,11 @@ export class ModalComponent implements OnInit, OnDestroy {
111111
set scrollable(value: boolean) {
112112
this._scrollable = coerceBooleanProperty(value);
113113
}
114+
114115
get scrollable(): boolean {
115116
return this._scrollable;
116117
}
118+
117119
private _scrollable = false;
118120

119121
/**
@@ -123,35 +125,36 @@ export class ModalComponent implements OnInit, OnDestroy {
123125
@Input()
124126
set visible(value: boolean) {
125127
const newValue = coerceBooleanProperty(value);
126-
if(this._visible !== newValue) {
128+
if (this._visible !== newValue) {
127129
this._visible = newValue;
128130
this.setBackdrop(this.backdrop !== false && newValue);
129131
this.setBodyStyles(newValue);
130132
this.visibleChange.emit(newValue);
131133
}
132134
}
135+
133136
get visible(): boolean {
134137
return this._visible;
135138
}
139+
136140
private _visible!: boolean;
137141

138142
/**
139143
* Event triggered on modal dismiss.
140144
*/
141145
@Output() visibleChange = new EventEmitter<boolean>();
142146

143-
@ViewChild(ModalContentComponent, {read: ElementRef}) modalContent!: ElementRef;
147+
@ViewChild(ModalContentComponent, { read: ElementRef }) modalContent!: ElementRef;
144148
private activeBackdrop!: any;
145149
private stateToggleSubscription!: Subscription;
146150
private inBoundingClientRect!: boolean;
147151

148-
149152
@HostBinding('class')
150153
get hostClasses(): any {
151154
return {
152155
modal: true,
153156
fade: this.transition,
154-
show: this.show,
157+
show: this.show
155158
};
156159
}
157160

@@ -170,14 +173,16 @@ export class ModalComponent implements OnInit, OnDestroy {
170173
return this.visible ? 'visible' : 'hidden';
171174
}
172175

173-
private _show = true;
174176
get show(): boolean {
175177
return this.visible && this._show;
176178
}
179+
177180
set show(value: boolean) {
178181
this._show = value;
179182
}
180183

184+
private _show = true;
185+
181186
private get scrollbarWidth() {
182187
// https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
183188
const documentWidth = this.document.documentElement.clientWidth;
@@ -187,28 +192,21 @@ export class ModalComponent implements OnInit, OnDestroy {
187192

188193
@HostListener('@showHide.start', ['$event'])
189194
animateStart(event: AnimationEvent) {
190-
this.renderer.setStyle(this.hostElement.nativeElement, 'overflow-y', 'hidden');
191-
this.show = this.visible;
195+
const scrollbarWidth = this.scrollbarWidth;
196+
if (event.toState === 'visible') {
197+
this.renderer.setStyle(this.document.body, 'overflow', 'hidden');
198+
this.renderer.setStyle(this.document.body, 'padding-right', scrollbarWidth);
199+
}
192200
}
193201

194202
@HostListener('@showHide.done', ['$event'])
195203
animateDone(event: AnimationEvent) {
196-
const scrollbarWidth = this.scrollbarWidth;
197204
setTimeout(() => {
198-
if (event.toState === 'visible') {
199-
this.inBoundingClientRect = this.modalContent?.nativeElement?.getBoundingClientRect().height <= this.document?.documentElement.clientHeight;
200-
if (!this.inBoundingClientRect) {
201-
this.renderer.setStyle(this.document.body, 'overflow-y', 'hidden');
202-
this.renderer.setStyle(this.document.body, 'padding-right', scrollbarWidth);
203-
} else {
204-
this.renderer.removeStyle(this.document.body, 'overflow-y');
205-
this.renderer.removeStyle(this.document.body, 'padding-right');
206-
}
207-
if (this.fullscreen === true) {
208-
this.renderer.setStyle(this.document.body, 'overflow-y', 'hidden');
209-
}
210-
this.renderer.removeStyle(this.hostElement.nativeElement, 'overflow-y');
205+
if (event.toState === 'hidden') {
206+
this.renderer.removeStyle(this.document.body, 'overflow');
207+
this.renderer.removeStyle(this.document.body, 'padding-right');
211208
}
209+
this.show = this.visible;
212210
});
213211
}
214212

@@ -218,7 +216,7 @@ export class ModalComponent implements OnInit, OnDestroy {
218216
if (this.backdrop === 'static') {
219217
this.setStaticBackdrop();
220218
} else {
221-
this.modalService.toggle({show: false, modal: this});
219+
this.modalService.toggle({ show: false, modal: this });
222220
}
223221
}
224222
}
@@ -241,15 +239,15 @@ export class ModalComponent implements OnInit, OnDestroy {
241239
this.setStaticBackdrop();
242240
return;
243241
}
244-
this.modalService.toggle({show: false, modal: this});
242+
this.modalService.toggle({ show: false, modal: this });
245243
}
246244

247245
ngOnInit(): void {
248246
this.stateToggleSubscribe();
249247
}
250248

251249
ngOnDestroy(): void {
252-
this.modalService.toggle({show: false, modal: this});
250+
this.modalService.toggle({ show: false, modal: this });
253251
this.stateToggleSubscribe(false);
254252
}
255253

@@ -283,16 +281,11 @@ export class ModalComponent implements OnInit, OnDestroy {
283281

284282
private setBodyStyles(open: boolean): void {
285283
if (open) {
286-
if (this.fullscreen === true) {
287-
this.renderer.setStyle(this.document.body, 'overflow-y', 'hidden');
288-
}
289284
if (this.backdrop === true) {
290285
this.renderer.addClass(this.document.body, 'modal-open');
291286
}
292287
} else {
293288
this.renderer.removeClass(this.document.body, 'modal-open');
294-
this.renderer.removeStyle(this.document.body, 'overflow-y');
295-
this.renderer.removeStyle(this.document.body, 'padding-right');
296289
}
297290
}
298291

@@ -303,7 +296,7 @@ export class ModalComponent implements OnInit, OnDestroy {
303296
setTimeout(() => {
304297
this.renderer.removeClass(this.hostElement.nativeElement, 'modal-static');
305298
this.renderer.removeStyle(this.hostElement.nativeElement, 'overflow-y');
306-
}, 400);
299+
}, 300);
307300
}
308301
}
309302
}

0 commit comments

Comments
 (0)