Ionic Nifty Modal

The Modal is a standard component nowadays in web applications, often used for logins or notifications, and it's become standard in mobile devices as well. It's doubly important on mobile considering it's constrained window size and navigational space.

Ionic similarly has a Modal for hybrid app development and as you guessed...it's called $ionicModal. The only caveat to using Ionic Modal is that it only supports one animation, slide-in-up it's prohibitive when you want to present a unique look and feel to your app. Although, there may be an expansion of the supported animations in our future.

Additionally, Ionic Modal is fullscreen by default, which is not my desired look most of the time. I like a centered modal with margins. $ionicPopup is an alternative but I like that a fully customizable external template is loaded via promise with $ionicModal.

And so I put together an additional CSS file to be included in index.html to get the Modal that I'm looking for, one that is horizontally/vertically centered and includes variety with animations. The animations are not my own and were sourced from Codrops and bounce.js, two libraries of CSS animations created by incredibly talented individuals. Their licenses are attached to their github pages.

Codrops bounce.js

Install

To get started, execute the following line in your bash terminal. You should then have nifty.modal.css available under /bower_components or whichever directory has been specified to be the recipient of bower components.

$ bower install ionic-nifty-modal

index.html

There's nothing too complicated here...just include nifty.modal.css in the head of index.html. The ionic template below is the template used in the codepen example above. It iterates over the CSS classes available in nifty.modal.css and produces a button that pops open the modal with each individual animation.

...
<link href="bower_components/ionic-nifty-modal/nifty.modal.css" rel="stylesheet">  
...

<body ng-app="starter">

  <ion-pane>
    <ion-header-bar class="bar-stable">
      <h1 class="title">Ionic Nifty Modal</h1>
    </ion-header-bar>
    <ion-content class="padding">
      <div ng-controller="MyController">

        <button ng-repeat="class in modalClasses" class="button button-full button-assertive" ng-click="openModal(class)">{{ class }}</button>

      </div>
    </ion-content>
  </ion-pane>
</body>  

my-modal.html

my-modal.html is the template loaded into the modal. Below, the template been enclosed by script tags because it's been included in the same file as index.html but it can be externalized into its own .html file (minus the script tags).

<script id="my-modal.html" type="text/ng-template">  
  <ion-modal-view class="ion-nifty-modal">
    <div class="ion-modal-content-custom">
      <ion-content class="padding">
        <button class="button button-full button-positive" ng-click="closeModal()">Close Modal</button>
      </ion-content>
    </div>
  </ion-modal-view>
</script>  

Controller

The controller logic is nearly identical to the code example in the $ionicModal docs. The sole exception is that I've enclosed the promise $ionicModal.fromTemplateUrl inside $scope.openModal so that the modal enters with the specified animation. In your own productions, avoid this syntax and do it as specified in the docs.

angular.module('starter', ['ionic'])

.controller('MyController', function($scope, $ionicModal) {
  $scope.modalClasses = ['slide-in-up', 'slide-in-down', 'fade-in-scale', 'fade-in-right', 'fade-in-left', 'newspaper', 'jelly', 'road-runner', 'splat', 'spin', 'swoosh', 'fold-unfold'];

  $scope.openModal = function(animation) {
    $ionicModal.fromTemplateUrl('my-modal.html', {
      scope: $scope,
      animation: animation
    }).then(function(modal) {
      $scope.modal = modal;
      $scope.modal.show();
    });
  };
  $scope.closeModal = function() {
    $scope.modal.hide();
  };
  //Cleanup the modal when we're done with it!
  $scope.$on('$destroy', function() {
    $scope.modal.remove();
  });
  // Execute action on hide modal
  $scope.$on('modal.hidden', function() {
    // Execute action
  });
  // Execute action on remove modal
  $scope.$on('modal.removed', function() {
    // Execute action
  });
});

CSS

The CSS below are the specifications for centering the modal. Rather than being fullscreen, it will take up 90% of the width of the window and be 300px tall.

.ion-nifty-modal {
  width: 90%;
  min-height: 0 !important;
  height: 300px !important;
  top: 25%;
  left: 5%;
  right: 5%;
  bottom: 5%;
  background-color: transparent;
  border-radius: 10px;
  -webkit-box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.5);
  box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.5); }

.ion-nifty-modal .ion-modal-content-custom {
  width: 100%;
  height: 100%;
  color: #FFF;
  background-color: #333;
  border-radius: 10px; }

/* Fix modal backdrop for smaller devices */
@media (max-width: 679px) {
  .active .modal-backdrop-bg {
    opacity: .5; }
  .modal-backdrop-bg {
    -webkit-transition: opacity 300ms ease-in-out;
    transition: opacity 300ms ease-in-out;
    background-color: #000;
    opacity: 0; } }

Options

And lastly, here are all the animation classes available with ioni-nifty-modal. The first half are CSS transitions from Codrops and the second are keyframe animations from bounce.js.

Enjoy!

Class Type
`slide-in-up` transition
`slide-in-down` transition
`fade-in-scale` transition
`fade-in-right` transition
`fade-in-left` transition
`newspaper` transition
`jelly` keyframe
`road-runner` keyframe
`splat` keyframe
`spin` keyframe
`swoosh` keyframe
`fold-unfold` keyframe