Integrate YouTube API With Angular

In this tutorial, we’ll learn how to integrate a YouTube API in Angular.

Introduction :

The YouTube Data API lets you incorporate functions normally executed on the YouTube website into your own website or application. We can retrieve a list of different types of resources from the API. A resource represents a type of item that comprises part of the YouTube experience, such as a video, a playlist, or a subscription.

First you need to set YouTube API key to integrate it in the project.

Set up the YouTube API

To get API key follow the below steps:

  1. Go to the Google developer console to create a new project.
  2.  Here when you create new project it will show you in below list,
  3.  Select a project.
  4. In the left sidebar, select library & enable YouTube Data API v3.
  5. Navigate to the credentials page by clicking on Credential located on the sidebar menu.
  6. Click on the + CREATE CREDENTIALS button located at the top of the page and select API key. A new API key should be created.

Create New Project

Create a new project from terminal in VS code by using following command.

ng new YouTubeAPI

here we need to create component for search box and container.

Create a new module called shared by running the following command in the terminal.

ng g module shared

now let’s create a service in this module by using following command in terminal.

ng g service shared/services/search

write the code in search.service.ts file as below:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SearchService {
  private API_URL = 'https://www.googleapis.com/youtube/v3/search';
  private API_KEY = 'YOUR API KEY';
  constructor(private http: HttpClient) {}

  getVideos(query: string): Observable <any> {
    const url = `${this.API_URL}?q=${query}&key=${this.API_KEY}&part=snippet&type=video&maxResults=10`;
    return this.http.get(url)
      .pipe(
        map((response: any) => response.items)
      );
  }
}

The getVideos method receives a search query string passed in from the input component, which we have to create. It then uses the http get method to send off a request to the URL constructed. It returns a response that we handle with the map operator. The list of YouTube video details is stored in the response.item object.

Now create interface. Run following command

ng g interface video

Add the following code in interface

export interface Video {
    videoId: string;
    videoUrl: string;
    channelId: string;
    channelUrl: string;
    channelTitle: string;
    title: string;
    publishedAt: Date;
    description: string;
    thumbnail: string;
}

We will be using Semantic-UI to provide styling to our application.

Add the following line in index.html file

<link rel=”stylesheet” type=”text/css” href=”https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.5/dist/semantic.min.css”>
Now, let’s create a component to enable to user to input string whatever they want to search on YouTube. Run Following Command in terminal.
ng g c search/search-input
Write code in search-input.component.html file as below.
<div class="ui four column grid">
  <div class="ten wide column centered">
    <div class="ui fluid action input">
      <input
        #input
        type="text"
        placeholder="Search for a video...">
    </div>
  </div>
</div>

Next, add following code in search-input.component.ts file.

import { Component, ElementRef, EventEmitter, Output, ViewChild,  AfterViewInit } from '@angular/core';
import { fromEvent,distinctUntilChanged } from 'rxjs';
import { debounceTime, pluck } from 'rxjs/operators';

@Component({
  selector: 'app-search-input',
  templateUrl: './search-input.component.html',
  styleUrls: ['./search-input.component.css']
})
export class SearchInputComponent implements  AfterViewInit {

  @ViewChild('input') inputElement!: ElementRef;
  @Output() search: EventEmitter<string> = new EventEmitter<string>();
  constructor() { }

    ngAfterViewInit() {
      if (this.inputElement) {
        fromEvent(this.inputElement.nativeElement, 'keyup')
          .pipe(
              debounceTime(500),
              pluck('target', 'value'),
              distinctUntilChanged(),
          )
          .subscribe(
          value => { this.search.emit(this.inputElement.nativeElement.value)}
        )
      }
    } 
}

ViewChild (‘input’) gives us access to the input element defined in the HTML file. ‘input’ is a selector that refers to the #input template reference variable we previously added to the input element in the HTML file.

formEvent is used to set up event listeners on a specific element.

debounceTime used to control the rate of user input.

distinctUntilChanged() ensures that the current value is different from the last value.Run Following Command in terminal.
Now, create search-list component. This component receive a list of videos from the parent component and renders it in the view.
ng g c search/search-list
Add the code in search-list.component.ts file
import { Component, Input, OnInit } from '@angular/core';
import { Video } from '../../../shared/models/search.interface';

@Component({
  selector: 'app-search-list',
  templateUrl: './search-list.component.html',
  styleUrls: ['./search-list.component.css']
})
export class SearchListComponent implements OnInit {

  @Input() videos: Video[] | undefined;
  constructor() { }

  ngOnInit(): void {
  }

}

Here, Input decorator is used to get vidoes list from the parent component.

Open the search-list.html file and paste the following code in this.
search-list.component.html file
<div class="ui four column grid">
    <div class="column" *ngFor="let video of videos">
      <div class="ui card">
        <div class="image">
          <img [src]="video.thumbnail">
        </div>
        <div class="content">
          <a class="header" style="margin: 1em 0 1em 0;">{{ video.title }}</a>
          <div class="meta">
            <span class="date" style="font-weight: bolder;">
              <a [href]="video.channelUrl" target="_blank">{{ video.channelTitle }}</a>
            </span>
            <span class="ui right floated date" style="font-weight: bolder;">{{ video.publishedAt | date:'mediumDate' }}</span>
          </div>
          <div class="description">
            {{ video.description?.slice(0,50) }}...
          </div>
        </div>
        <a [href]="video.videoUrl" target="_blank" class="extra content">
          <button class="ui right floated tiny red right labeled icon button">
            <i class="external alternate icon"></i>
            Watch
          </button>
        </a>
      </div>
    </div>
  </div>

let’s create parent component for search-list component.

ng g c search/search-container

This component should be able to get user inputs from the search-component component. It should pass this over to the search service, which does the  operations and returns the expected result. The result should be send to the search-list component, where it will be rendered.

 

serch-container.component.ts 
import { Component, OnInit } from '@angular/core';
import { Video } from 'src/app/shared/models/search.interface';
import { SearchService } from 'src/app/shared/services/search.service';

@Component({
  selector: 'app-search-container',
  templateUrl: './search-container.component.html',
  styleUrls: ['./search-container.component.css']
})
export class SearchContainerComponent {

  inputTouched = false;
  loading = false;
  videos: Video[] = [];
  constructor(private searchService: SearchService) { }
  
  handleSearch(inputValue: string) {
    this.loading = true;
    this.searchService.getVideos(inputValue)
      .subscribe((items : any) => {
        this.videos = items.map((item => {
          return {
            title: item.snippet.title,
            videoId: item.id.videoId,
            videoUrl: `https://www.youtube.com/watch?v=${item.id.videoId}`,
            channelId: item.snippet.channelId,
            channelUrl: `https://www.youtube.com/channel/${item.snippet.channelId}`,
            channelTitle: item.snippet.channelTitle,
            description: item.snippet.description,
            publishedAt: new Date(item.snippet.publishedAt),
            thumbnail: item.snippet.thumbnails.high.url
          };
        });
        this.inputTouched = true;
        this.loading = false;
      });
    }

}

serch-container.component.html

<div>
    <app-search-input (search)="handleSearch($event)"></app-search-input>
    <div *ngIf="inputTouched && !videos.length" class="ui four wide column centered grid" style="margin: 3rem;">
      <div class="ui raised aligned segment red warning message">
        <i class="warning icon"></i>
        <span class="ui centered" style="margin: 0 auto;">No Video Found</span>
      </div>
    </div>
    <div *ngIf="loading" style="margin: 3rem;">
      <div class="ui active centered inline loader"></div>
    </div>
    <app-search-list *ngIf="!loading" [videos]="videos"></app-search-list>
  </div>

 

Here, serach servise use the HttpClient, so we have to import HttpClientModule in app.module.ts file.

Paste the following code in app.module.ts file.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {HttpClientModule} from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SearchInputComponent } from './search/components/search-input/search-input.component';
import { SearchListComponent } from './search/components/search-list/search-list.component';
import { SearchContainerComponent } from './search/container/search-container/search-container.component';

@NgModule({
  declarations: [
    AppComponent,
    SearchInputComponent,
    SearchListComponent,
    SearchContainerComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

<div class="ui centered grid" style="margin-top: 3rem;">
  <div class="fourteen wide column">
    <h1 class="ui centered aligned header">
      <span style="vertical-align: middle;">Youtube Search </span>
      <img src="/assets/youtube-icon.png" alt="">
    </h1>
    <app-search-container></app-search-container>
  </div>
</div>

OUTPUT:

 

 

 

Submit a Comment

Your email address will not be published.

Subscribe

Select Categories