Створення вебсайту, схожого на IMDB, за допомогою Angular, TailwindCss та Imdb collect API #частина2

pic

кінцевий результат

Спочатку отримайте API Token на платформі collect api https://collectapi.com/ та увійдіть за допомогою вашого акаунту Google.
pic

на панелі керування collect api виберіть "Free Plan Available", потім виберіть IMDB API

pic

натисніть кнопку "show", потім перейдіть на вкладку "pricing", виберіть безкоштовний план і підпишіться, збережіть ваш API token, який можна знайти на сторінці профілю, цей API token буде використовуватися для авторизації вашого акаунту.

Встановлення Angular & TailwindCss

Створіть новий проєкт на Angular за допомогою Angular CLI ng new [ім'я проекту]

ng new imdb-clone

зверніть увагу, що у цьому проекті використовується Angular версії 19

Після завершення встановлення, додайте TailwindCss до проєкту, для цього перейдіть у папку проєкту та введіть команду

npm install -D tailwindcss postcss autoprefixer  

npx tailwindcss init

Далі відредагуйте файл tailwind.config.js наступним чином:

/** @type {import('tailwindcss').Config} */  
module.exports = {  
 content: [  
 "./src/**/*.{html,ts}",  
 ],  
 theme: {  
 extend: {},  
 },  
 plugins: [],  
}

Потім відредагуйте файл ./src/styles.css якщо ви використовуєте CSS

@tailwind base;  
@tailwind components;  
@tailwind utilities;

або ./src/styles.scss якщо використовуєте SCSS

@import "tailwindcss/base";  
@import "tailwindcss/utilities";  
@import "tailwindcss/components";

Після цього спробуйте відредагувати файл app.component.html, видаліть весь стандартний код, що додається Angular, та вставте це:

    Hello world!   

Якщо вигляд відповідає зображенню нижче, то встановлення Tailwind пройшло успішно!
pic

Перехоплювачі (Interceptors)

Оскільки API, який ми використовуємо, вимагає токен авторизації, доцільно застосувати перехоплювачі (interceptors) у Angular.

Що таке перехоплювачі (Interceptors)?

Коротко кажучи, перехоплювачі в Angular — це інструмент для модифікації запитів та відповідей перед їх відправленням або отриманням сервером. Вони використовуються для обробки загальних логік, таких як:
- Додавання headers до кожного запиту.
- Обробка authentication або токенів для оновлення.
- Обробка або модифікація відповіді від сервера.
- Глобальне оброблення помилок (error handling).

Перехоплювачі працюють подібно до "middleware", тобто кожен запит проходить через перехоплювачі перед тим, як потрапити на сервер, а кожна відповідь проходить через перехоплювач перед тим, як потрапити до додатку.

Створення Перехоплювача

Ми можемо створити перехоплювач за допомогою Angular CLI за командою "ng generate interceptor [назваInterceptor]".

Приклад:

ng generate interceptor Authorization

Файл перехоплювача буде створено, і тимчасово структура проєкту виглядатиме так:

pic

Тепер ми інжектуємо файл перехоплювача в додаток. Відкрийте файл src/app/app.config.ts і оновіть код до наступного:

import { ApplicationConfig } from '@angular/core';  
import { provideRouter } from '@angular/router';  
import { routes } from './app.routes';  
import { provideHttpClient, withInterceptors } from '@angular/common/http';  
import { authorizationInterceptor } from './authorization.interceptor';  

export const appConfig: ApplicationConfig = {  
 providers: [provideRouter(routes), provideHttpClient(withInterceptors([authorizationInterceptor]))]  
};  

що відбувається в коді вище: ми додаємо _provideHttpClient_, який відповідає за надання HTTP клієнта в додаток Angular. Потім всередині нього використовується `withInterceptors` для додавання одного або кількох перехоплювачів (interceptors) до HTTP клієнта. І, нарешті, `authorizationInterceptor` — це перехоплювач (функція або клас), який використовується для модифікації HTTP запитів, що були створені. Пізніше ми додамо заголовок Authorization з токеном, отриманим з Collect API в попередньому кроці.

Модифікуємо файл _authorization.interceptor.ts_

import { HttpInterceptorFn } from '@angular/common/http';

export const authorizationInterceptor: HttpInterceptorFn = (req, next) => {
const authReq = req.clone({
setHeaders: {
Authorization: 'paste api key disini'
}
})
return next(authReq);
};
```

Зверніть увагу: переконайтеся, що ви скопіювали весь API ключ, починаючи з 'apikey xxxxxxx'.

На даному етапі ми успішно отримали API ключ з Collect API, ініціалізували новий проєкт з Angular та Tailwind, і створили перехоплювач (interceptor).
Далі ми створимо сторінку для відображення списку фільмів, деталей фільму та форму для пошуку фільмів, яка буде взаємодіяти з компонентами, формами, сервісами.

Додавання головної сторінки

Тепер створимо просту сторінку як головну сторінку. У цьому підручнику ми не будемо створювати сторінку з дизайном, схожим на сайт IMDb, ви можете налаштувати її на свій розсуд.

Створимо модуль з назвою Home за допомогою Angular CLI

ng g m home

Потім створимо компонент home-index у папці home

ng g c home/home-index --standalone=false

pic

за замовчуванням, коли ви створюєте компонент, який не є standalone, Angular CLI автоматично оновлює файл модуля для декларування компонента, щоб він був розпізнаний

— standalone=false є прапором Angular для того, щоб компонент не був standalone, оскільки в Angular 19 за замовчуванням кожен компонент, який генерується, є standalone, і в цьому підручнику я не хочу використовувати standalone компонент.

Додаємо компонент для деталей фільму

ng g c home/detail-film --standalone=false

Редагуємо файл app_.component.html, щоб він виглядав так

Imdb Lite
Home
import { Component } from '@angular/core';  
import { RouterLink, RouterOutlet } from '@angular/router';  

@Component({  
  selector: 'app-root',  
  standalone: true,  
  imports: [RouterOutlet, RouterLink],  
  templateUrl: './app.component.html',  
  styleUrl: './app.component.scss'  
})  
export class AppComponent {  
  title = 'angular-x-collect-api';  
}  

Редагуємо файл home.module.ts

import { NgModule } from '@angular/core';  
import { CommonModule } from '@angular/common';  
import { HomeIndexComponent } from './home-index/home-index.component';  
import { DetailFilmComponent } from './detail-film/detail-film.component';  
import { RouterModule, Routes } from '@angular/router';  

const routes: Routes = [  
  {  
    path: '',  
    pathMatch: 'full',  
    redirectTo: ''  
  },  
  {  
    path: '',  
    component: HomeIndexComponent  
  },  
  {  
    path: 'film/:id',  
    component: DetailFilmComponent  
  }  
]  

@NgModule({  
  declarations: [  
    HomeIndexComponent,  
    DetailFilmComponent  
  ],  
  imports: [  
    CommonModule,  
    RouterModule.forChild(routes)  
  ]  
})  
export class HomeModule { }  

Редагуємо файл app.routes.ts

import { Routes } from '@angular/router';  

export const routes: Routes = [  
  {  
    path: '',  
    loadChildren: () => import('../app/home/home.module').then(m => m.HomeModule)  
  }  
];  

RouterModule, RouterOutlet, RouterLink і loadChildren мають різні функції. Далі ми створимо пояснення про ці функції, чому і коли їх слід використовувати.

Редагуємо файл home-index.component.html

  Film 1  
  Film 2  
  Film 3  
  Film 4  

Після цього спробуйте запустити додаток Angular. Якщо відображення відповідає зображенню нижче, значить, ми успішно створили просту сторінку.

pic
Далі ми додамо функцію для форми пошуку фільму, щоб дані введені в поле могли бути захоплені і використані як параметри в URL.

Редагуємо файл app.component.ts так:

import { Component } from '@angular/core';  
import { FormControl, ReactiveFormsModule } from '@angular/forms';  
import {  
  ActivatedRoute,  
  Router,  
  RouterLink,  
  RouterOutlet,  
} from '@angular/router';  
import { debounceTime, distinctUntilChanged } from 'rxjs';  

@Component({  
  selector: 'app-root',  
  standalone: true,  
  imports: [RouterOutlet, RouterLink, ReactiveFormsModule],  
  templateUrl: './app.component.html',  
  styleUrl: './app.component.scss',  
})  
export class AppComponent {  
  title = 'angular-x-collect-api';  

  searchName = new FormControl("marvel");  

  constructor(private router: Router, private route: ActivatedRoute) {  

    this.searchName.valueChanges  
      .pipe(  
        debounceTime(300) /* Чекаємо 300 мс після того, як користувач перестане друкувати */,  
        distinctUntilChanged() /* Обробляємо тільки змінені значення */  
      )  
      .subscribe((value) => {  
        this.router.navigate([], {  
          queryParams: {  
            query: value  
          },  
          queryParamsHandling:  
            'merge' /* Для збереження інших параметрів запиту */,  
        });  
      });  
  }  

  deleteFilter() {  
    this.searchName.reset();  
  }  
}

Редагуємо файл app.component.html

Imdb Lite  
Home  
    @if (searchName.value) {        ❌           }    

Запустіть додаток, і результат буде таким:

pic

Сервіс

Створимо файл сервісу для отримання даних з API за допомогою Angular CLI

ng generate service home/film

Потім у папці home додаємо ще один файл з назвою imdb.type.ts.

Редагуємо файл imdb.type.ts

export type IMDBRatingType = {  
  Source: string;  
  Value: string;  
};  

export type IMDBListType = {  
  Title: string;  
  Year: string;  
  Poster: string;  
  Type: string;  
  imdbID: string;  
};  

export type IMDBFilmDetailType = {  
  Title: string;  
  Year: string;  
  Rated: string;  
  Released: string;  
  Runtime: string;  
  Genre: string;  
  Director: string;  
  Writer: string;  
  Actors: string;  
  Plot: string;  
  Language: string;  
  Country: string;  
  Awards: string;  
  Poster: string;  
  Ratings: IMDBRatingType[];  
  Metascore: string;  
  imdbRating: string;  
  imdbVotes: string;  
  imdbID: string;  
  Type: string;  
  DVD: string;  
  BoxOffice: string;  
  Production: string;  
  Website: string;  
  Response: string;  
};

Редагуємо файл film.service.ts

import { HttpClient } from '@angular/common/http';  
import { Injectable } from '@angular/core';  
import { Params } from '@angular/router';  
import { IMDBListType } from './imdb.type';  

@Injectable({  
  providedIn: 'root',  
})  
export class FilmService {  
  ApiUrl = 'https://api.collectapi.com/imdb/imdbSearchByName';  
  constructor(private http: HttpClient) {}  

  getAllFilm(param: Params){  
    return this.http.get<{ result: IMDBListType[]}>(this.ApiUrl, {  
      params: param  
    })  
  }  
}

Ми успішно створили сервіс. Якщо все вірно, можемо продовжити створення головної сторінки.
Якщо ви ще не зрозуміли, що таке сервіс в Angular, ви можете ознайомитись з офіційною документацією Angular або прочитати статтю за наступним посиланням:

https://medium.com/@rikijoniiskandar97/mengenal-angular-framework-modern-untuk-pengembangan-web-part1-d8a1f4225b41

Відкрийте файл home-index.component.ts і додайте наступний код:

import { Component } from '@angular/core';  
import { IMDBListType } from '../imdb.type';  
import { FilmService } from '../film.service';  
import { ActivatedRoute, Params } from '@angular/router';  

@Component({  
  selector: 'app-home-index',  
  templateUrl: './home-index.component.html',  
  styleUrl: './home-index.component.scss',  
})  
export class HomeIndexComponent {  
  filmCollections: IMDBListType[] = [];  

  params: Params = {}  

  constructor(  
    private filmService: FilmService,  
    private route: ActivatedRoute  
  ){  
    this.route.parent?.queryParamMap.subscribe((param) => {  
      if(param.has('query')) {  
        this.params['query'] = param.get('query')  
      } else {  
        this.params['query'] = 'marvel'  
      }  
      this.filmService.getAllFilm(this.params).subscribe((res) => {  
        if(res) this.filmCollections = res.result ?? []  
      })  
    })  
  }  
}

Далі редагуємо файл home-index.component.html:

    @for (film of filmCollections; track $index) {    
{{film.Type}}  
{{film.Title}}    
{{film.Year}}  
    }       

    @empty {    
      @if (params && !filmCollections.length) {    
        Немає даних для пошуку {{params['query']}}  
      } @else {    
        Фільми не знайдені  
      }    
    }   

Запустіть додаток і перевірте, чи працює все як має бути. Якщо виникають помилки, перевірте код і переконайтесь, що нічого не пропустили.

Наступним кроком ми перейдемо до створення сторінки для деталей фільму. Раніше ми вже створили основну сторінку для відображення деталей фільму за imdbID. Спробуйте!

Перекладено з: Membuat website mirip IMDB menggunakan Angular, TailwindCss & Imdb collect API #part2

Leave a Reply

Your email address will not be published. Required fields are marked *