Ionic Item Expand

This is a simple variant implementation of an accordion using...

...you guessed it, Ionic. (everything on this blog is about Ionic or Angular)

The Ionic team has already released an example of an accordion using expandable groups but for a recent project, I was needing a rendition of an accordion that expanded text or more precesely overflowed content. You can see the Ionic Accordion below:

With a tweek here and there, I created the top-most codepen example and given it the name Ionic Item Expand. So sit back, take a breather...there's only light reading below.



The Markup

ng-repeat is used to iterate an object on scope called items and it spits out an individual item with a title and text property. Nothing special but the most notable addition is the ternary operator inside ng-class that checks whether an item is shown or not. If true, include this class. If not, include the other class.

<body ng-app="ionicApp" ng-controller="MyCtrl">

    <ion-header-bar class="bar-positive">
      <h1 class="title">Ionic Item Expand</h1>
    </ion-header-bar>

    <ion-content>

      <ion-list>

        <ion-item ng-repeat="item in items" class="item item-text-wrap">
          <div ng-class="isItemShown(item) ? 'item-expand active' : 'item-expand inactive'">
            <h2>{{ item.title }}</h2>
            <p>{{ item.text }}</p>
          </div>
          <div ng-click="toggleItem(item)" class="item-expand-footer">
            <i ng-class="isItemShown(item) ? 'ion-ios-minus-outline' : 'ion-ios-plus-outline'"></i>
            {{ isGroupShown(item) ? 'Less' : 'More' }}
          </div>
        </ion-item>

      </ion-list>

    </ion-content>

  </body>


The Controller

The function that acts as the conditional for the ternary operator in ng-class is defined inside the controller and attached to its scope. This is a snippet taken from the Ionic Accordion example but named differently to make more sense within this context.

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

.controller('MyCtrl', function($scope) {
  $scope.items = [{
      title: '1',
      text: '...'
    },{
      title: '2',
      text: '...'
    },{
      title: '3',
      text: '...'
    },{
      title: '4',
      text: '...'
    },{
      title: '5',
      text: '...'
  }];

  $scope.toggleItem= function(item) {
    if ($scope.isItemShown(item)) {
      $scope.shownItem = null;
    } else {
      $scope.shownItem = item;
    }
  };
  $scope.isItemShown = function(item) {
    return $scope.shownItem === item;
  };

});


The CSS

Lastly and most importantly, because this is where the real magic of this example lies, is the CSS. The default height of each item is defined in the max-height property of the .item-expand class. So, if you'd like to modify the default height, there is where you'd look.

When the ternary operator inside ng-class returns false, .inactive is applied to the item which also includes a linear-gradient that blurs the under-contents of the div. When the ternatory operator returns true, .active is applied and the div transitions to the maximum height of the content. Unfortunately, it is necessary to specify a max-height in .active and it's best to estimate it's value to be somewhere just a touch beyond the maximum height you'd expect it to reach.

/* CORE */
.item-expand {
  position: relative;
  width: 100%;
  max-height: 60px;
  transition: max-height 0.1s ease-out;
  overflow: hidden;
}

.item-expand.inactive:after {
  content: "";
  position: absolute;
  bottom: 0px;
  left: 0;
  height: 15px;
  width: 100%;
  display: block;
  background-image: -webkit-gradient(
    linear,
    left top,
    left bottom,
    color-stop(0, rgba(255, 255, 255, 0)),
    color-stop(1, rgba(255, 255, 255, 1))
  );
  background-image: -o-linear-gradient(bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
  background-image: -moz-linear-gradient(bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
  background-image: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
  background-image: -ms-linear-gradient(bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
  background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
}

.item-expand.active {
  max-height: 200px;
  transition: max-height 0.3s ease-out;
}


/* DEMO */
.item-expand-footer {
  color: red;
  margin-top: 10px;
}

.item-expand-footer i {
  margin-right: 10px;
}


And that's it! Below are links to the Codepen demo and to the Github repo.

Demo GitHub