The Official Ionic Blog

Build amazing native and progressive web apps with HTML5

Raymond Camden is a Developer Advocate at IBM and frequently writes about Ionic on his blog, where this post originally appeared.

A little over a year ago, I wrote a post (“Ionic Example: ion-slide-box”) that demonstrated how to use the ion-slide-box component with Ionic 1. A few days ago, a reader asked if I could update that post to work with Ionic 2. I’ve done that and am now going to share some of the code from the updated version.

In case you don’t feel like reading the previous entry, the demo was rather simple. It made use of the Bing Image Search API to fetch pictures based on your input. For context, here’s an example of how it looked for Ionic 1 and iOS:

image-search_cat

I’m beginning to think it is physically impossible for me to do a demo that doesn’t involve cats. Anyway, let’s talk about the Ionic 2 version. First, the view:

<ion-header>
  <ion-navbar>
    <ion-title>
      Image Search
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>

  <ion-item>
    <ion-input type="search" placeholder="Search" [(ngModel)]="search"></ion-input>
  </ion-item>

  <button ion-button full (click)="doSearch()">Search</button>

  <ion-slides [options]="mySlideOptions">
    <ion-slide *ngFor="let slide of slides">
      <img [src]="slide.MediaUrl">
    </ion-slide>
  </ion-slides>

</ion-content>

In form, it’s similar to the V1 version of app, but while V1 still had a mix of HTML and Ionic components, this is nearly 100% Ionic tag-based. The only non-Ionic component there is the button tag, and even it uses an argument to flag it as being Ionic-controlled anyway. If you’re still new to Angular 2 (like me!), you should pay special attention to the new syntax used for event handling: (click)="doSearch()" and two way binding: [(ngModel)]="search". Another tweak is to iteration. While V1 had ng-repeat, I’m using *ngFor in V2. All in all, the view here is simpler than my previous version. (But to be clear, the previous version did everything in one HTML file as it was so simple. I could have separated out the view into its own file.) Now, let’s take a look at the code. First, the code for the view:

import { Component } from [email protected]/core';
import { NavController } from 'ionic-angular';
import { ImageSearch } from '../../providers/image-search';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
  providers:[ImageSearch]
})
export class HomePage {

  search:string;
  slides:any[];
  mySlideOptions = {
    pager:true
  };

  constructor(public navCtrl: NavController, public searchProvider:ImageSearch) {
  }

  doSearch() {
    console.log('searching for '+this.search);
    this.searchProvider.search(this.search).subscribe(data => {
      console.log(data);
      this.slides = data;
    });
  }

}

There isn’t anything too scary here. I’ve got one method, doSearch, that simply fires off a call to my provider for Bing searches. The only real interesting part is mySlideOptions. If you want to tweak how the slide works, you can’t just pass arguments via the component tag. That kinda sucks in my opinion, but I’m guessing there is a good reason for that. I had tried adding pager="true" to my ion-slides tag, but that didn’t work. I had to create a variable and then bind to it from the view. Again, that bugs me. I can get over it, though.

The provider is now all wrapped up in fancy Oberservables and crap, which frankly still confuse the hell out of me. But I got it working. The hardest thing was figuring out how to do headers.

import { Injectable } from [email protected]/core';
import { Http, Headers} from [email protected]/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';

/*
  Generated class for the ImageSearch provider.

  See https://angular.io/docs/ts/latest/guide/dependency-injection.html
  for more info on providers and Angular 2 DI.
*/
@Injectable()
export class ImageSearch {

  appid = "fgQ7ve/sV/eB3NN/+fDK9ohhRWj1z1us4eIbidcsTBM";
  rooturl = "https://api.datamarket.azure.com/Bing/Search/v1/Image?$format=json&Query='";

  constructor(public http: Http) {
    this.http = http;
  }

  search(term:string) {

      let url = this.rooturl + encodeURIComponent(term) + "'&$top=10";

      let headers = new Headers();
      headers.append('Authorization', 'Basic '+ btoa(this.appid + ':' + this.appid));
      return this.http.get(url,{headers:headers})
        .map(res => res.json())
        .map(data => data.d.results);

  }

}

And yep, that’s my Bing key. I’ll probably regret sharing it. So how does it look? Here’s an iOS example:

islide1

Right away, you’ll notice the pager isn’t actually there. I’m not sure why that is failing to show up because it does show up when running ionic serve. I could definitely try to size that image a bit nicer in the view, but for a quick demo, I got over it.

A few minutes later…

So I was wrapping up this blog post when I started chatting about it over on the Ionic Slack channel. Mike and others helped me discover a few things.

First, you know how I complained about having to create a variable in my JS code just to handle a simple option? Turns out you can do it all in the view–thanks, Mike:

<ion-slides [options]="{pager:true}">

I added that and then removed the code from home.ts, making it even simpler. But I still had the bug with the pager not showing up. It clearly worked in ionic serve, see?

islide2

So wtf, right? Then I remembered – Chrome DevTools has a Responsive Mode. What happens when we turn that on?

islide3

Boom. Right away I see the same bug… and I notice the scrollbar. I scroll down and see…

islide4

Yep, my slides portion is just too big. On my iOS simulator, I scrolled down and confirmed. Sigh. So (and again, with help from smart folks on the Slack channel!), I ended up styling the ion-slides components:

<ion-slides [options]="{pager:true}" style="max-height:400px">

I use a set max of 400px, which isn’t terribly cross platform compatible, but it helped:

islide5

Perfect! Except this is what you see on initial load:

islide6

Ugh. So I tried going back to having options defined in JavaScript and simply changing it when data was loaded, but that didn’t work. I then tried getting a pointer to the slider object and updating it that way. It also didn’t work.

Ugh again. So I went back to a simple inline option declaration but also hid the entire slider:

<ion-slides [options]="{pager:true}" style="max-height:400px"  *ngIf="haveData">

I then modified my code to default haveData:

import { Component, ViewChild } from [email protected]/core';
import { NavController, Slides } from 'ionic-angular';
import { ImageSearch } from '../../providers/image-search';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
  providers:[ImageSearch]
})
export class HomePage {

  search:string;
  slides:any[];
  haveData:boolean = false;

  constructor(public navCtrl: NavController, public searchProvider:ImageSearch) {
  }

  doSearch() {
    console.log('searching for '+this.search);
    this.searchProvider.search(this.search).subscribe(data => {
      console.log(data);
      if(data.length >= 1) {
        this.haveData=true;
        this.slides = data;
      }
    });
  }

}

And now it works perfectly! To be fair, this still needs a nice “loading” widget UI when searching, but as I mainly wanted to focus on the slides, I figure I should try to keep this simple. The full source code for this demo may be found here.

Let me know if you have any questions or comments below.

  • Jacek Kurowski

    it’s possible to use html5 video?

    • http://www.raymondcamdencom/ Raymond Camden

      Try it and see. 🙂 I’d guess it would work fine – let us know.

  • http://www.VisitAnyPlace.com/ Miguel Carrasco Q.

    providers:[ImageSearch] ? Are you using RC2 logic?

    • http://www.raymondcamdencom/ Raymond Camden

      Yep.

      • http://www.VisitAnyPlace.com/ Miguel Carrasco Q.

        I see the repo, and the providers can be defined in src/app/app.module.ts according to https://github.com/driftyco/ionic/blob/master/CHANGELOG.md#steps-to-upgrade-to-rc0 (step 8)

        • http://www.raymondcamdencom/ Raymond Camden

          … ok… and? I’m sorry – are you asking a question?

          • http://www.VisitAnyPlace.com/ Miguel Carrasco Q.

            I’m just pointing out. For those who are waiting for new releases (RCx) and see a tutorial like this, which has code from previous versions, can be confusing.

          • http://www.raymondcamdencom/ Raymond Camden

            Oh, ok, sure. Now it makes sense. 🙂

  • Anton

    Raymond, good day ! Is it possible in Ionic 2 zoom on image (pinch) ?

    • Aamir

      +1

    • http://www.raymondcamdencom/ Raymond Camden

      Sorry – no idea on that. I assume you tried and it didn’t work?

      • Anton

        I didn’t find any default solution in Ionic2 how to zoom image by pinch.

    • Yann Braga

      Most of the custom features are not listed in ionic docs, but slider is actually a wrapper of swiper (http://idangero.us/swiper/api/#.WC4cbHUrLIU).
      I haven’t tried it myself, but there are two options you could use: (zoom: true) and (zoomToggle: true).

  • Yen Jacobs

    I enabled scrolling on the slides component with overflow-y: scroll. Is it possible to position the pager always to the bottom of the scroll view so it don’t overlaps other components?

    • http://www.raymondcamdencom/ Raymond Camden

      I’d like to know that too. As I said in the article, I had some issues w/ the positioning.

      • Ralph Schaer

        It looks quite nice when you add a card around the slides.
        The pager is at the bottom of the card.

  • jack ode

    the ionic framework webiste menu nav doesn’t scroll up or down. im using an Ubuntu OS with chrome browser. please help out, i just wanna scroll through the APIs

    • http://www.raymondcamdencom/ Raymond Camden

      You are reporting a website bug on this blog post?

  • Ruud

    Would be a bad idea to check on the data directly for enabling the slider?
    0″>

    • http://www.raymondcamdencom/ Raymond Camden

      That looks like a good improvement. I kinda like how mine is a bit more clear, but yours is simpler though.