By Danyal Zia | 2/6/2017 | General |Beginners

Building a YouTube search application with Ionic 2

Building a YouTube search application with Ionic 2

Introducing the amazing power of framework through a real-life example.

(Note: This is the first article in the series of Ionic 2. Stay tuned for more!)

In my previous article, I have written about the difference, and pros/cons of Ionic 2, ReactNative and NativeScript, but my article was mostly conceptual, therefore some people might have complained about its quality, so why not show our readers an actual practical example of the framework? Also, it makes sense to talk about one framework first, and then move on to other frameworks.

Ionic 2 is a hybrid mobile development framework designed solely for creating mobile applications with a single code-base, while ReactNative and NativeScript claim to be as close to native as possible, meaning Ionic 2 has the edge over these platforms when it comes to prototyping applications or speed of development. But, ReactNative and NativeScript provide easy integration to native UI components, so the experience will be truer to native UI and faster in performance.

It’s not very difficult to make the transition to Ionic 2 if you are coming from AngularJS 2 (which I assume you are, considering you are one of my readers!). If you remember my previous articles, I once wrote about how to use HTTP (and its services) in AngularJS 2. A moment later, you will witness the emergence of a same structure, forcing you to question if you are still working with AngularJS 2 or Ionic 2.

In this article, I am going to build an application containing a YouTube search using the Ionic 2. Let’s get started!

Building a YouTube search application with Ionic 2

Ionic 2 is a kind of upgrade of Ionic 1, or you can say that it takes some features from previous versions, while improving (or adding) extra features. Even though you can use native functionalities through Cordova plugins (with the help of Ionic-Native), I won’t be covering it at this moment (perhaps in the next article?). I will demonstrate an application that can run on any supported platform.

The architecture of Ionic 2 is modular, similar to AngularJS 2, in fact, when building applications for Ionic 2 you would get the similar feeling, but there are some changes (which you will understand soon). In Ionic 2, every page or component has its own folder as part of its component-based structure, meaning whenever you create a new component through Ionic CLI, then a separate folder is created for the page that contains its .ts (or component) code and their respective HTML and CSS/Sass code.

But, we won’t be using advanced AngularJS 2 features like Feature Modules, Shared Modules, Core Modules, etc. and rather just stick with @NgModule or standard approach provided with Ionic 2. I will first create a sample application, and then we will build our application from the same code-base.

The fact that I am writing the code in TypeScript/AngularJS 2 is because I know that you have read my previous articles on AngularJS 2 and therefore you will have a seamless transition.



Creating a project

We won’t be creating complex apps, but a simple YouTube API app that has a search input field. Assuming you have already installed the Cordova and Ionic (including their respective CLI!), you can use the Ionic 2 right away!

$ ionic start YouTubeAPI blank --v2

 

Ionic has four templates available: tabs, sidemenu, blank and tutorial. We are using the blank template here, because we simply need to provide an input field for testing YouTube API, but if you visit their tutorial site (https://ionicframework.com/docs/v2/setup/tutorial/), you will notice that they actually use the tutorial template for the start-up projects.

If you do “ionic serve” you will see nothing but a very basic template.

The cool thing here is that the same AngularJS 2 tools would be used, so for example, we would be using Chrome DevTools for debugging, meaning the errors on the JavaScript side can be seen from the “Console” tab.

The project structure is a lot of similar to AngularJS 2 structure. For example, the app starts with “src/index.html” which is the main entry point of the app. You should notice something in it:

<ion-app></ion-app>

This is our main selector (remember the selectors in our previous AngularJS 2 tutorials?). The “src/” folder contains all the files that we are going to work with. If you open “src/app/” folder, you will find “app.module.ts”, which is our main entry point of the app. Following is its contents:

app.module.ts

 

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
@NgModule({
 declarations: [
   MyApp,
   HomePage
 ],
 imports: [
   IonicModule.forRoot(MyApp)
 ],
 bootstrap: [IonicApp],
 entryComponents: [
   MyApp,
   HomePage
 ],
 providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}

As we are using AngularJS 2 model structure, we are loading every components in this class. IonicModule.forRoot(MyApp) is for bootstrapping the MyApp module in order to assure that it’s an Ionic module.

After the build, the files are moved to “www/” folder, so we won’t be touching it for now. “config.xml” is for the configuration when the application needs to be installed on a device. “plugins” folder contain Cordova plugins (which we are not using, so let’s not touch it!). “resources” folder contain resources like icons, and splash screens.

Ionic 2 contains pages, which are like activities in Android. Pages are put in a stack, and so they are retrieved on a principle of LIFO (Last In First Out).

To create new pages:

$ionic g page page-name

By default, you would find “home” directory in “pages” folder, which contains a very basic code.

home.html

 

<ion-header>
 <ion-navbar>
   <ion-title>
     Ionic Blank
   </ion-title>
 </ion-navbar>
</ion-header>
<ion-content padding>
 The world is your oyster.
 <p>
   If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will be your guide.
 </p>
</ion-content>

Here, the <ion-header> defines the header of the page, within that  <ion-navbar> is used for navigation bar, <ion-title> displays the page title. </ion-content> shows that it contains the contents, we have provided some padding in it. We will see more selectors later.

Delete the “home” folder and also make sure to delete all the instances of home in “app.module.ts”. So, let’s create our YouTube page component:

$ionic g page youtube

In your “app.component.ts”, import the YoutubePage component and change your “rootPage” to “YoutubePage”. Following is its contents:

app.component.ts

 

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { YoutubePage } from '../pages/youtube/youtube';
@Component({
 templateUrl: 'app.html'
})
export class MyApp {
 rootPage = YoutubePage;
 constructor(platform: Platform) {
   platform.ready().then(() => {
     // Okay, so the platform is ready and our plugins are available.
     // Here you can do any higher level native things you might need.
     StatusBar.styleDefault();
     Splashscreen.hide();
   });
 }
}

Make sure to include it in your “app.module.ts”. You can refer to the previous code provided in this article, and simply change “Home” to “YoutubePage” wherever you find it on the page.

We are not using several pages in our application, so you won’t see many menus (we will cover the menus in next articles!).

For the YouTube API, we will use the same code as our previous AngularJS 2 project that we adopted from ng-book 2. We will modify it a bit. Copy the following content to “youtube.ts”:

youtube.ts

 

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import {
 Injectable,
 OnInit,
 ElementRef,
 EventEmitter,
 Inject
} from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
export var YOUTUBE_API_KEY: string = 'AIzaSyDOfT_BO81aEZScosfTYMruJobmpjqNeEk';
export var YOUTUBE_API_URL: string = 'https://www.googleapis.com/youtube/v3/search';
class SearchResult {
 id: string;
 title: string;
 description: string;
 thumbnailUrl: string;
 videoUrl: string;
 constructor(obj?: any) {
   this.id              = obj && obj.id             || null;
   this.title           = obj && obj.title          || null;
   this.description     = obj && obj.description    || null;
   this.thumbnailUrl    = obj && obj.thumbnailUrl   || null;
   this.videoUrl        = obj && obj.videoUrl       ||
                           `https://www.youtube.com/watch?v=${this.id}`;
 }
}
@Injectable()
export class YouTubeService {
 constructor(public http: Http,
             @Inject(YOUTUBE_API_KEY) private apiKey: string,
             @Inject(YOUTUBE_API_URL) private apiUrl: string) {
 }
 search(query: string): Observable<SearchResult[]> {
   let params: string = [
     `q=${query}`,
     `key=${this.apiKey}`,
     `part=snippet`,
     `type=video`,
     `maxResults=10`
   ].join('&');
   let queryUrl: string = `${this.apiUrl}?${params}`;
   return this.http.get(queryUrl)
     .map((response: Response) => {
       return (<any>response.json()).items.map(item => {
         return new SearchResult({
           id: item.id.videoId,
           title: item.snippet.title,
           description: item.snippet.description,
           thumbnailUrl: item.snippet.thumbnails.high.url
         });
       });
     });
 }
}
export var youTubeServiceInjectables: Array<any> = [
 {provide: YouTubeService, useClass: YouTubeService},
 {provide: YOUTUBE_API_KEY, useValue: YOUTUBE_API_KEY},
 {provide: YOUTUBE_API_URL, useValue: YOUTUBE_API_URL}
];
@Component({
 outputs: ['loading', 'results'],
 selector: 'search-box',
 template: `
   <p>Enter something in the field and see the asynchronous results!</p>
   <input type="text" class="form-control" placeholder="Search" autofocus>
 `
})
export class SearchBox implements OnInit {
 loading: EventEmitter<boolean> = new EventEmitter<boolean>();
 results: EventEmitter<SearchResult[]> = new EventEmitter<SearchResult[]>();
 constructor(public youtube: YouTubeService,
            private el: ElementRef) {
 }
 ngOnInit(): void {
   Observable.fromEvent(this.el.nativeElement, 'keyup')
     .map((e: any) => e.target.value)
     .filter((text: string) => text.length > 1)
     .debounceTime(250)                         
     .do(() => this.loading.next(true))         
     .map((query: string) => this.youtube.search(query))
     .switch()
     .subscribe(
       (results: SearchResult[]) => {
         this.loading.next(false);
         this.results.next(results);
       },
       (err: any) => {
         console.log(err);
         this.loading.next(false);
       },
       () => {
         this.loading.next(false);
       }
     );
 }
}
@Component({
 inputs: ['result'],
 selector: 'search-result',
 template: `
  <div class="col-sm-6 col-md-3">
     <div class="thumbnail">
       <img src="{{result.thumbnailUrl}}">
       <div class="caption">
         <h3>{{result.title}}</h3>
         <p>{{result.description}}</p>
         <p><a href="{{result.videoUrl}}"
              class="btn btn-default" role="button">Watch</a></p>
       </div>
     </div>
   </div>
 `
})
export class SearchResultComponent {
 result: SearchResult;
}
@Component({
 selector: 'page-youtube',
 templateUrl: 'youtube.html'
})
export class YoutubePage {
 constructor(public navCtrl: NavController, public navParams: NavParams) {}
 ionViewDidLoad() {
   console.log('ionViewDidLoad YoutubePage');
 }
  results: SearchResult[];
 updateResults(results: SearchResult[]): void {
   this.results = results;
 }
}

Now copy the following content to “youtube.html”:

youtube.html

 

<ion-header>
 <ion-navbar>
   <ion-title>YouTube API</ion-title>
 </ion-navbar>
</ion-header>
<ion-content padding>
<div class='container'>
 <div class="page-header">
<h2>YouTube Search
</h2>
 </div>
 <div class="row">
<div class="input-group input-group-lg col-md-12">
 <search-box
(loading)="loading = $event"
(results)="updateResults($event)"
 ></search-box>
</div>
 </div>
 <div class="row">
<search-result
 *ngFor="let result of results"
 [result]="result">
</search-result>
 </div>
</div>
</ion-content>

You can see that I have added the YouTube HTML code within the <ion-content> element.

Make sure to include all the pages in “app.module.ts”. Following is its complete content:

app.module.ts

 

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { YoutubePage } from '../pages/youtube/youtube';
import { youTubeServiceInjectables } from '../pages/youtube/youtube';
import { SearchResultComponent } from '../pages/youtube/youtube';
import { SearchBox } from '../pages/youtube/youtube';
@NgModule({
 declarations: [
   MyApp,
   YoutubePage,
SearchResultComponent,
SearchBox
 ],
 imports: [
   IonicModule.forRoot(MyApp)
 ],
 bootstrap: [IonicApp],
 entryComponents: [
   MyApp,
   YoutubePage,
SearchResultComponent,
SearchBox
 ],
 providers: [youTubeServiceInjectables, {provide: ErrorHandler, useClass: IonicErrorHandler}],
 exports: [
   YoutubePage
 ]
})
export class AppModule {}

…and that’s all! You can “ionic serve” now to see the results!

At this moment, I like to highlight that Ionic 2 provides cool Progressive Web App (PWA) demos here (http://pwa.ionic.io/), so you can run the apps as if they are applications on your mobile devices! For instance, you get the app-like experience from the applications that are actually built on web technologies, for example, you can use your mouse (on PC) to turn the page or to slide something aside, as if your mouse is your hand on a touchscreen!

Building for android

As our application is already finished, why not build the .apk out of it to test on our mobile devices? Thankfully, Ionic CLI provides very easy commands that builds the application for the android (or iOS) for you.

First you need to add the platform for the android:

 

$ cordova add platform android

This will create a folder for the android (under “platform/” directory). Now, run the following command:

$ cordova build --release android

 

If you get the errors, then make sure that recent Android SDK is installed on your device AND that the PATH is set correctly for the SDK. This will create an “unsigned” application in “platforms/android/build/outputs/apk” directory. This is enough for running the application on your device assuming that you have enabled the installation of unsigned applications in your device.

For making the application “signed”, you can check this link (https://ionicframework.com/docs/guide/publishing.html).

You can also emulate android app on your PC:

$ cordova build --release android

 

Make sure that Android Emulator is installed on your computer (refer to Android SDK Manager for that).

Conclusion

Thus, so far, you can see the real example of Ionic 2 of the YouTube API. You can enjoy and run the application in your mobile devices, and see that it’s hard to distinguish this app from the app created from a purely native code. In the next articles, I will discuss Ionic 2 in further depth.

If you have any questions, then please ask in the comment section below!

By Danyal Zia | 2/6/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
User photo
1650
Martin Cohen
Over 5 years in cross-platform development.
Mobile | Cross Platform Frameworks
View Profile
User photo
1490
Ronan McCarthy
Cross-Platform & Web developer.
Web | Mobile and 6 more
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now