Ionic Example: ion-slide-box

One of my favorite parts of the Ionic framework is the ion-slide-box. It is a simple directive that allows you to create a pretty handy little widget for your mobile application. (Widget isn't really the best word.) The ion-slide-box directive lets you embed a set of images (or random HTML) and then display one item at a time. Their docs have a great little animated gif that I'm going to steal to demonstrate exactly what this looks like:

slideBox

What makes this feature so cool is how darn easy it is to use. For example, here is the sample code to create a slide box:

<ion-slide-box on-slide-changed="slideHasChanged($index)">
  <ion-slide>
    <div class="box blue"><h1>BLUE</h1></div>
  </ion-slide>
  <ion-slide>
    <div class="box yellow"><h1>YELLOW</h1></div>
  </ion-slide>
  <ion-slide>
    <div class="box pink"><h1>PINK</h1></div>
  </ion-slide>
</ion-slide-box>

This is incredibly simple. I thought I'd build a simple demo of this feature that tied the slides to a dynamic result. I thought I'd use the Bing Image Search API since it worked well for me in the past (Adding voice-based search to a PhoneGap app). I set up a simple view that included a form field and button top.

iOS Simulator Screen Shot Sep 16, 2015, 10.42.15 AM

When you enter a term, it will then display the results in a slidebox:

iOS Simulator Screen Shot Sep 16, 2015, 10.44.18 AM

Notice the little gray balls at the bottom - they provide a way for you to know where you are in the slide list (and you can turn that feature off if you want). Now let's take a look at the code. First, I'll show the HTML.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
  </head>
  <body ng-app="starter">

    <ion-pane>
      <ion-header-bar class="bar-stable">
        <h1 class="title">Image Search</h1>
      </ion-header-bar>
      <ion-content class="padding" ng-controller="MainCtrl">
                        
                <div class="list">
                <label class="item item-input">
                    <input type="search" placeholder="Search" ng-model="search">
                </label>
                <button class="button button-full button-assertive" ng-click="doSearch()">Search</button>
                </div>

                <ion-slide-box>
                    <ion-slide ng-repeat="image in images">
                        <img ng-src="{{image.MediaUrl}}" style="width:300px;height:300px;margin:auto;display:block" >
                    </ion-slide>
                </ion-slide-box>
                
      </ion-content>
    </ion-pane>
  </body>
</html>

Most of this is boilerplate Ionic code, but you can seem my ion-slide-box is using a dynamic ion-slide list. That's really all there is to it. I could include more in the slide, like the image title, source, etc., but I wanted it simple. Now let's look at the code.

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('starter', ['ionic'])

.controller("MainCtrl", function($scope, ImageSearch, $ionicSlideBoxDelegate) {

    $scope.images = [];
        
    $scope.doSearch = function() {
        if(!$scope.search) return;
        console.log("search for ", $scope.search);    
        ImageSearch.getImages($scope.search).then(function(results) {
            $scope.images = results.data.d.results;
            setTimeout(function() {
                $ionicSlideBoxDelegate.slide(0);
                $ionicSlideBoxDelegate.update();
                $scope.$apply();
            });
        });
    };
    
})

.service("ImageSearch", function($http) {
    
    return {
        getImages:function(term) {
            var appid = "fgQ7ve/sV/eB3NN/+fDK9ohhRWj1z1us4eIbidcsTBM";
            $http.defaults.headers.common['Authorization'] = 'Basic ' + btoa(appid + ':' + appid);
            return $http.get("https://api.datamarket.azure.com/Bing/Search/v1/Image?$format=json&Query='"+escape(term)+"'&$top=10");
        }   
    };
    
})

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

The Bing API changed a bit since my last demo, but for the most part is still relatively easy to use. Their documentation wasn't always very direct. Outside of that I had no real issues. And yes - that's my appid included in the source code. This is a perfect example of where I could use a MobileFirst HTTP Adapter. I described this process here: Working with MP3s, ID3, and PhoneGap/Cordova – Adding IBM MobileFirst. Using the adapter would also let me modify how Bing returns results. I could use lowercase and I could return just the URLs, making my mobile perform better since less network data would be going back and forth.

Outside of the service it is a simple matter of updating the scope - but I ran into an interesting issue. I noticed that if I was on slide X and searched for something else...

iOS Simulator Screen Shot Sep 16, 2015, 10.52.39 AM

then the "current slide" remained at where you were before. That's where $ionicSlideBoxDelegate.slide(0) comes into play. But doing so introduced a weird bug involving AngularJS and digests. I hate those things. Mike Hartington from the Ionic team helped me out on Slack and recommended the timeout/$scope.$apply() solution you see above. That made it work perfectly.

All in all, a simple demo, but I hope this is useful for folks. You can find the complete source code for this demo here: https://github.com/cfjedimaster/Cordova-Examples/tree/master/ionicslidebox1

Like This?

If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can also subscribe to the email feed to get notified of new posts.

Want to read more like this?