Angular Modals

We were developing a cross device web app in Angular 1.6.5 front-end and Node 4.4.5 back-end (tough to get modern tooling). A lot of our business flow relied on modals with: inputs, long texts, buttons, check buttons, and all their friends. Originally our modals were the normal $mdialog from Angular.

This is the example from Angular.js sight. Ours looked exactly the same.

We copied this nearly word for word and it worked great on desktop browsers. Exhibit A.

However, these modals EXPLODE on mobile. Particularly when a form is involved. The problem is these modals are determining the screen size and the screen size changes when the keyboard is in view on a mobile device. We had cases where if a user is in a form and the keyboard is up and then they open a modal, then the modal would break. Our modals also broke when the screen was rotated to landscape mode. Explode is a strong word, it’s more like annoying user experience.

Examples

Opening a calendar modal on iPhone 6S.

Then scroll down a little.

It just scrolled the modal, not the page.

NOTE: To fix this, make sure you have your background scrolling disabled while the modal is open. The solution we found has easy fix.

BUTTTT, there is still the issue of trying to select something.

Keyboard pops up, no date selected and I can’t see the modal either.

The styling is off on mobile, even for the demo online.

What’s Up with that Button?

Here’s the normal flow on Samsung Galaxy.

  1. Open it and everything is fine.

2. Try to type and it pushes the modal to the top of the screen out of view of what I am typing. Again, because of the screen size changing.

Designers have a field day.

Fixing It

We scrapped the entire $mdDialog and used this ModalService to open them instead

First:

npm install angular-modal-service

Next:

Our Modals were all opened like so:

openModal = (template) => {
return this.ModalService.showModal({
template: template,
bodyClass: ‘disable-scrolling’,
controller: ($scope, close) => {
‘ngInject’;
$scope.close = close;
$scope.currentFilterIndex = this.currentFilterIndex;
$scope.accept = () => {
this.someMethod();
close();
}
}
});
};

It’s simple, but incredibly effective for solving the cross device and mobile problem. You also don’t need bootstrap.

This was an incredibly easy way to prevent scrolling in the background when opening a modal:

We made out own disableBodyScrolling css class:

body.disable-scrolling {
overflow: hidden !important;
width: 100%;
height: 100%;
@media (max-width: 760px) {
//This is for mobile devices to prevent scrolling in the background
position: fixed !important;
}
}

Some Simple CSS for the modals (this is entirely customizable).

.modal {
background: rgba(30, 30, 30, 0.8);
line-height: 1.5em;
top: 0;
left: 0;
z-index: 999999999;
width: 100%;
height: 100%;
position: fixed;
overflow-y: scroll;
&-body {
box-shadow: 0 3px 6px 3px rgba(0, 0, 0, 0.4);
position: absolute;
z-index: 9999999999;
top: 50px;
margin-bottom: 50px;
left: 50%;
width: $md; //this is a variable set to 700px.
margin-left: -$md/2;
padding: 25px 50px;
background: white;
border-radius: 6px;
text-align: center;
}
header {
text-align: center;
padding-bottom: 10px;
font-size: 30px;
line-height: 45px;
}
section {
text-align: center;
padding-bottom: 10px;
p {
font-size: 14px;
}
}
section .no-padding {
padding-bottom: 0px;
}
footer {
.md-button {
display: block;
width: 100%;
margin: 10px auto;
padding: 10px 20px;
}
.md-button .btn-primary {
background: #329CCE;
color: white;
border-radius: 4px;
&.btn-outline {
border: 1px solid $aimme-link;
background: transparent;
padding: 6px 5px;
color: $aimme-link;
}
}
}
}

Then finally the actual modal templates looks like so.

<div class=”modal”>
<div class=”modal-body”>
<header></header>
<section>

</section>
<footer>

</footer>
</div>
</div>

This allowed us to control the modal size purely through css, not javascript like $mdDialog.

This solved our problems with Angular Modals on Mobile!