Как сделать поиск пользователей по Github используя Angular

в 6:21, , рубрики: angular, javascript, React, SvelteJs, Разработка веб-сайтов

image

Эта статья является ответом на:
Как сделать поиск пользователей по GitHub используя React + RxJS 6 + Recompose,
Как сделать поиск пользователей по GitHub без React + RxJS 6 + Recompose,
Как сделать поиск пользователей по Github используя VanillaJS.

Целью статьи является:
— показать, что на Angular тоже можно быстро написать простое приложение, хотя это не его основной конек,
— показать плюсы приложения на Angular.

Целью статьи НЕ является:
— разжиганеие очередного холивара.

Всем кому интересно прошу под кат.

Подготовка

Для работы с Angular необходимо установить глобально angular CLI

npm install -g @angular/cli

Создаем новое приложение

ng new github-ui
cd github-ui

Сразу создадим комопоненты пользователя и ошибки, и сервис для получения данных с github

ng generate component components/user
ng generate component components/error
ng generate service services/github

И подключим их в основной модуль приложения.
Так-же подключим модули HttpClient (для работы с http запросами) и ReactiveForms (для работы с формами).

app.module.ts

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

import { AppComponent } from './app.component';
import { UserComponent } from './components/user/user.component';
import { ErrorComponent } from './components/error/error.component';
import { GithubService } from './services/github.service';

@NgModule({
  declarations: [AppComponent, UserComponent, ErrorComponent],
  imports: [BrowserModule, ReactiveFormsModule, HttpClient],
  providers: [GithubService],
  bootstrap: [AppComponent]
})
export class AppModule {}

Модели данных

Т.к. Angular использует Typescript, а Typescript дает нам типизацию, то хорошей практикой является описывать модели данных.
Это дает следующие плсы:
— удобный автокомплит при работе с приложением,
— проверка совпадения типов на стадии компиляции,
— дает другим разработчикам понять с какими данными они работают.

models/user.model.ts

export class User {
  login: string;
  id: number;
  node_id: string;
  avatar_url: string;
  gravatar_id: string;
  url: string;
  html_url: string;
  followers_url: string;
  following_url: string;
  gists_url: string;
  starred_url: string;
  subscriptions_url: string;
  organizations_url: string;
  repos_url: string;
  events_url: string;
  received_events_url: string;
  type: string;
  site_admin: boolean;
  name: string;
  company: string;
  blog: string;
  location: string;
  email: string;
  hireable: string;
  bio: string;
  public_repos: number;
  public_gists: number;
  followers: number;
  following: number;
  created_at: string;
  updated_at: string;
}

Сервис для получения данных

Работу с запросами на сервер в Angular принято выносить в сервисы.
В созданный ранее сервис добавим метод для получения данных пользователя.

services/github.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../models/user.model';

@Injectable()
export class GithubService {

  // Подключаем модуль для работы с http
  constructor(private http: HttpClient) {}

  // Метод для запроса пользователя
  getUser(name: string): Observable<User> {
    const url = `https://api.github.com/users/${name}`;
    return this.http.get<User>(url);
  }
}

Поиск пользователя

В Angular из коробки встроен RxJs. С помощью него и модуля работы с формами мы можем подписаться на изменение значения контрола, и получить данные пользователя.

app.component.html

<div class="container"
  [class.ready]="!!user">
  <input [formControl]="findControl"
    placeholder="GitHub username" />

  <app-user *ngIf="user"
    [user]="user"></app-user>

  <app-error *ngIf="error"></app-error>
</div>

app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { GithubService } from './services/github.service';
import { User } from './models/user.model';
import { filter, switchMap, debounceTime, catchError } from 'rxjs/operators';
import { EMPTY } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  // Контрол для поиска пользователей
  findControl = new FormControl();
  // Ошибка поиска
  error: boolean = false;
  // Найденный пользователь
  user: User = null;

  // Подключение githubService для поиска пользователя
  constructor(private githubService: GithubService) {}

  // Хук инициализации компонента
  ngOnInit() {
    this.findControl.valueChanges
      .pipe(
        // Фильтруем если введено меньше двух символов
        filter(value => value.length > 2),
        // Ставим задержку одну секунду
        debounceTime(1000),
        // Запрашиваем данные пользователя
        switchMap(value =>
          this.githubService.getUser(value).pipe(
            // Обработка ошибок
            catchError(err => {
              this.user = null;
              this.error = true;
              return EMPTY;
            })
          )
        )
      )
      // Получение данных
      .subscribe(user => {
        this.user = user;
        this.error = false;
      });
  }
}

Остальные компоненты

Остальные компоненты являются «глупыми», т.е. не содержат в себе логики, а только отображают полученные данные.

user component

<div class="github-card user-card">
  <div class="header User"></div>
  <a class="avatar"
    [href]="'https://github.com/'+user.login">
      <img [src]="user.avatar_url+'&s=80'" [alt]="user.name" />
    </a>
  <div class="content">
    <h1>{{user.name}}</h1>
    <ul class="status">
      <li>
        <a [href]="'https://github.com/'+user.login+'?tab=repositories'">
            <strong>{{user.public_repos}}</strong>Repos
          </a>
      </li>
      <li>
        <a [href]="'https://gist.github.com/'+user.login">
            <strong>{{user.public_gists}}</strong>Gists
          </a>
      </li>
      <li>
        <a [href]="'https://github.com/'+user.login+'/followers'">
            <strong>{{user.followers}}</strong>Followers
          </a>
      </li>
    </ul>
  </div>
</div>

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { User } from '../../models/user.model';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent {
  @Input()
  user: User;
}

error component

<div class="error">
  <h2>Oops!</h2>
  <b>
    User not found.
  </b>
  <p>Please try searching again.</p>
</div>

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-error',
  templateUrl: './error.component.html',
  styleUrls: ['./error.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ErrorComponent {}

Плюсы использования Angular

— отделение получения данных от работы с ними,
— отделение шаблона от логики,
— четкая и понятная масштабируемая структура,
— встроенные модули для работы с формами и сервером,
— встроенный RxJs для ассинхронной работы,
— строгая типизация проверка на наличие ошибок при компиляции.

Исходный код

github
live demo

Выводы

Как было показано выше любое приложение (особенно небольшое) можно написать используя разные библиотеки, фреймворки или чистый JS.

Более важным является знание инструментов которые вы используете, и понимание на сколько они подходят в данной ситуации.

Всем успехов в изучении и чистого кода!

Автор: Климент

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js