Belajar HTTP Membuat Crud dan Fitur Search Angular Part 8 - Tutorial Programming & Digital Marketing

STAY HUNGRY STAY FOOLISH

Breaking

Home Top Ad

Tuesday, September 24, 2019

Belajar HTTP Membuat Crud dan Fitur Search Angular Part 8

bewoksatukosong.com | Hallo semuanya balik lagi dengan om bewok kali ini om bewok akan melanjutkan tutorial sebelumnya yang mana tutorial sebelumnya mengenai Routing dan kali ini kita akan belajar mengenai http lalu membuat crud dan juga kita membuat fitur search pada angular, ini bisa dibilang tutorial terakhir dalam angular. Oh iya bagi yang belum tau ini adalah tutorial series belajar angular 2019. Kalau kamu ingin melihat daftar tutorial-Nya bisa lihat dibawah ini ya 
Daftar Tutorial Angular 2019  
Nah kali ini kita akan menghubungkan httpClient yang mana artinya untuk menghubungkan data server real atau asli yang kita butuhkan adalah httpClient. Jadi kita tambahkan terlebih dahulu ya pada 
src/app/app.module.ts Nah jika kamu mengikuti tutorial ini sebelumnya, kalian harus install 
in-memory-web-api tetapi kalau kamu menggunakan http server kalian tidak perlu install ini. 

Kalian buka terminal lalu install ini
npm install angular-in-memory-web-api --save
Lalu kalian tambahkan pada app.module.ts, jadi seperti dibawah ini untuk app.module.ts keseluruhan saat ini ya
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FoodComponent } from './food/food.component'; 

import { FormsModule } from '@angular/forms';
import { FoodDetailComponent } from './food-detail/food-detail.component';
import { MessagesComponent } from './messages/messages.component';
import { DashboardComponent } from './dashboard/dashboard.component'; // Tambahkan forms module(1)
import { HttpClientModule } from '@angular/common/http';

import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';
import { FoodSearchComponent } from './food-search/food-search.component';
@NgModule({
  declarations: [
    AppComponent,
    FoodComponent,
    FoodDetailComponent,
    MessagesComponent,
    DashboardComponent,
    FoodSearchComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule,
    HttpClientInMemoryWebApiModule.forRoot(
      InMemoryDataService, { dataEncapsulation: false }
    )
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Selanjutnya kita akan menambahkan data fake, sebenarnya ini mirip seperti makanan-indo.ts tapi ini kita masukan pada service, buka terminal kalian lalu ketikan 
ng generate service InMemoryData
lalu kamu tambahkan kodingan di src/app/in-memory-data.service.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { Injectable } from '@angular/core';
import { Foods } from './foods';
@Injectable({
  providedIn: 'root'
})
export class InMemoryDataService implements InMemoryDbService {
 createDb() {
  const lapers = [
   { id: 10, name: 'nasi uduk' },
   { id: 11, name: 'nasi goreng' },
   { id: 12, name: 'semur jengkol' },
   { id: 13, name: 'soto betawi' },
   { id: 14, name: 'sop buntung' },
   { id: 15, name: 'sop iga' },
   { id: 16, name: 'bakwan' },
   { id: 17, name: 'gudeg' },
   { id: 18, name: 'mie ayam' },
   { id: 19, name: 'mie goreng' },
   { id: 20, name: 'telor dadar' }
  ];
  return {lapers};
 }

 genId(lapers: Foods[]): number {
  return lapers.length > 0 ? Math.max(...lapers.map(laper => laper.id)) + 1: 11;
 }

  constructor() { }
}
Mirip kan sama makanan-indo.ts
Lalu sekarang kita tambahkan httpClient dan httpHeaders pada food.service.ts dan jangan lupa kita tambahkan httpClient pada constructor & membuat method log pada food.service.ts dan juga
Kita juga menambahkan url api, jadi ibaratnya kita hit dari server.
import { Injectable } from '@angular/core';
// import foods & makanan-indo
import { Foods } from './foods';
import { MessageService } from './message.service'; 
// import rxjs observable
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class FoodService {

  private foodsUrl = 'api/lapers'; // url to web api

  httpOptions = {headers: new HttpHeaders({ 'Content-Type': 'application/json' })};

  constructor(private messageService: MessageService, private http: HttpClient) { }

Oke saatnya kita membuat errorhandling, jadi ketika error kita tau bagian mana yang error. Seperti biasa kita tambahkan pada src/app/food.service.ts pokoknya kalau masalah logic semuanya akan di taruh di service
food.service.ts
private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  private log(message: string) {
    this.messageService.add(`FoodService: ${message}`);
  }
}
Jadi secara keseluruhan untuk food.service.ts seperti dibawah ini ya
import { Injectable } from '@angular/core';
// import foods & makanan-indo
import { Foods } from './foods';
import { MessageService } from './message.service'; 
// import rxjs observable
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class FoodService {

  private foodsUrl = 'api/lapers'; // url to web api

  httpOptions = {headers: new HttpHeaders({ 'Content-Type': 'application/json' })};

  constructor(private messageService: MessageService, private http: HttpClient) { }

  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  private log(message: string) {
    this.messageService.add(`FoodService: ${message}`);
  }
}

Cara Membuat CRUD ( CREATE READ UPDATE DELETE) Angular 2019

READ

Oke pertama kita akan menampilkan data dan menampilkan data per ID 
Kalian buka src/app/food.service.ts 
 /** GET Foods from the server */
  getFoods(): Observable<Foods[]>{
    return this.http.get<Foods[]>(this.foodsUrl).pipe(tap(_ => this.log('fetched food')),
      catchError(this.handleError<Foods[]>('getFoods', []))
    );
  }

  getFood(id: number): Observable<Foods> {
    const url = `${this.foodsUrl}/${id}`;
    return this.http.get<Foods>(url).pipe(
      tap(_ => this.log(`fetched food id=${id}`)),
      catchError(this.handleError<Foods>(`getFood id=${id}`))
    );
  }

Kalian buka app/food/food.component.html
<h2>Makanan Favoritku</h2>
<!-- add form input -->
<div>
 <label>Food name:
  <input #foodName />
 </label>
 <button (click)="add(foodName.value); foodName.value=''">Add</button>
</div>
<ul class="lapers">
  <li *ngFor="let laper of lapers">
    <a routerLink="/detail/{{laper.id}}">
      <span class="badge">{{laper.id}}</span> {{laper.name}}
    </a>
  </li>
</ul>
Selanjutnya kalian buka app/food/food.component.ts
import { Component, OnInit } from '@angular/core';
import { Foods } from '../foods'; // tambahkan ini import foods.ts
import { FoodService } from '../food.service';

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

 lapers: Foods[];

  constructor(private foodService: FoodService) { }

  ngOnInit() {
   this.getFoods();
  }

  getFoods(): void {
    this.foodService.getFoods().subscribe(lapers => this.lapers = lapers);
  };
}
Selanjutnya kita akan menampilkan data per ID, kalian buka 
app/food/food-detail/food-detail.component.html
<div *ngIf="laper">
  <h2>{{laper.name | uppercase}} Details</h2>
  <div><span>id: </span>{{laper.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="laper.name" placeholder="name"/>
    </label>
  </div>
  <button (click)="goBack()">go back</button>
  <button (click)="save()">save</button>
</div>
app/food/food-detail/food-detail.component.ts
// tambahkan INPUT
import { Component, OnInit, Input } from '@angular/core';
// Tambahkan Foods dari foods
import { Foods } from '../foods';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';

import { FoodService }  from '../food.service';

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

 @Input() laper: Foods;

   constructor(
    private route: ActivatedRoute,
    private foodService: FoodService,
    private location: Location
  ) {}

  ngOnInit(): void {
    this.getFood();
  }

  getFood(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.foodService.getFood(id).subscribe(laper => this.laper = laper);
  }

  goBack(): void {
    this.location.back();
  }

  save(): void {
    this.foodService.updateFood(this.laper).subscribe(() => this.goBack());
  }
}
UPDATE
Selanjutnya kamu buka app/food.service.ts
 updateFood(laper: Foods): Observable<any> {
    return this.http.put(this.foodsUrl, laper, this.httpOptions).pipe(
       tap(_ => this.log(`update food id=${laper.id}`)), 
       catchError(this.handleError<any>('update food'))
    );
  }
Oke kalian buka app/food-detail/food-detail.component.ts
// tambahkan INPUT
import { Component, OnInit, Input } from '@angular/core';
// Tambahkan Foods dari foods
import { Foods } from '../foods';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';

import { FoodService }  from '../food.service';

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

 @Input() laper: Foods;

   constructor(
    private route: ActivatedRoute,
    private foodService: FoodService,
    private location: Location
  ) {}

  ngOnInit(): void {
    this.getFood();
  }

  getFood(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.foodService.getFood(id).subscribe(laper => this.laper = laper);
  }

  goBack(): void {
    this.location.back();
  }

  save(): void {
    this.foodService.updateFood(this.laper).subscribe(() => this.goBack());
  }
}
Oke kalian buka app/food-detail/food-detail.component.html
<div *ngIf="laper">
  <h2>{{laper.name | uppercase}} Details</h2>
  <div><span>id: </span>{{laper.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="laper.name" placeholder="name"/>
    </label>
  </div>
  <button (click)="goBack()">go back</button>
  <button (click)="save()">save</button>
</div>

CREATE

Selanjutnya kamu buka app/food.service.ts
  // add food
  addFood (laper: Foods): Observable<Foods> {
    return this.http.post<Foods>(this.foodsUrl, laper, this.httpOptions).pipe(tap((newFood: Foods) => this.log(`added food w/ id={newFood.id}`)), catchError(this.handleError<Foods>('addFood'))
    );
  }
Oke kalian buka app/food/food.component.ts
import { Component, OnInit } from '@angular/core';
import { Foods } from '../foods'; // tambahkan ini import foods.ts
import { FoodService } from '../food.service';

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

 lapers: Foods[];

  constructor(private foodService: FoodService) { }

  ngOnInit() {
   this.getFoods();
  }

  getFoods(): void {
    this.foodService.getFoods().subscribe(lapers => this.lapers = lapers);
  };

  // add click eventf
  add(name: string): void {
    name = name.trim();
    if (!name) { return; }
    this.foodService.addFood({ name } as Foods).subscribe(laper => {
      this.lapers.push(laper);
    });
  }
}
Oke kalian buka app/food/food.component.html
<h2>Makanan Favoritku</h2>
<!-- add form input -->
<div>
 <label>Food name:
  <input #foodName />
 </label>
 <button (click)="add(foodName.value); foodName.value=''">Add</button>
</div>
<ul class="lapers">
  <li *ngFor="let laper of lapers">
    <a routerLink="/detail/{{laper.id}}">
      <span class="badge">{{laper.id}}</span> {{laper.name}}
    </a>
  </li>
</ul>

DELETE

Selanjutnya kamu buka app/food.service.ts
  deleteFood (laper: Foods | number): Observable<Foods> {
    const id = typeof laper === 'number' ? laper : laper.id;
    const url = `${this.foodsUrl}/${id}`;

    return this.http.delete<Foods>(url, this.httpOptions).pipe(
      tap(_ => this.log(`deleted food id=${id}`)),
      catchError(this.handleError<Foods>('deleteFood'))
    );
  }
Oke kalian buka app/food/food.component.ts
  delete(laper: Foods): void {
    this.lapers = this.lapers.filter(h => h !== laper);
    this.foodService.deleteFood(laper).subscribe();
  }
Oke kalian buka app/food/food.component.html
<h2>Makanan Favoritku</h2>
<!-- add form input -->
<div>
 <label>Food name:
  <input #foodName />
 </label>
 <button (click)="add(foodName.value); foodName.value=''">Add</button>
</div>
<ul class="lapers">
  <li *ngFor="let laper of lapers">
    <a routerLink="/detail/{{laper.id}}">
      <span class="badge">{{laper.id}}</span> {{laper.name}}
    </a>
    <button class="delete" title="delete laper" (click)="delete(laper)">x</button>
  </li>
</ul>

Membuat Fitur Search

FYI kalau kamu ingin codingan fullnya bisa lihat paling bawah ya
Kita tambahkan pada src/app/food.service.ts
  // search food
  searchFoods(term: string): Observable<Foods[]> {
    if (!term.trim()) {
      return of([]);
    }

    return this.http.get<Foods[]>(`${this.foodsUrl}/?name=${term}`).pipe(
      tap(_ => this.log(`found food matching "${term}"`)),
      catchError(this.handleError<Foods[]>('searchFoods', []))
    );
  } 
Selanjutnya tambahkan <app-search-food> pada 
src/app/dashboard/dashboard.component.html
<h3>Top Foods</h3>
<div class="grid grid-pad">
  <a *ngFor="let laper of lapers" class="col-1-4"
    routerLink="/detail/{{laper.id}}">
  <div class="module laper">
    <h4>{{laper.name}}</h4>
  </div>
</a>
</div>

<app-food-search></app-food-search>

Untuk membuat fitur search kita butuh component baru oleh karena itu buka terminal kalian lalu ketikan
ng generate component food-search

Selanjutnya kamu tambahkan pada 
src/app/food-search/food-search.component.html
<div id="search-component">
 <h4><label for="search-box">Food Search</label></h4>

 <input #searchBox id="searchBox" (input)="search(searchBox.value)" />

 <ul class="search-result">
  <li *ngFor="let laper of lapers$ | async">
   <a routerLink="/detail/{{laper.id}}">
    {{laper.name}}
   </a>
  </li> 
 </ul>
</div>
Selanjutnya tambahkan juga  
src/app/food-search/food-search.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable, Subject } from 'rxjs';

import {
   debounceTime, distinctUntilChanged, switchMap
 } from 'rxjs/operators';

 import { Foods } from '../foods';
 import { FoodService } from '../food.service';

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

 lapers$: Observable<Foods[]>;
 private searchTerm = new Subject<string>();

  constructor(private foodService: FoodService) { }

  search(term: string): void {
   this.searchTerm.next(term);
  }

  ngOnInit(): void {
   this.lapers$ = this.searchTerm.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((term: string) => this.foodService.searchFoods(term)),
   );
  }

}



Kodingan Full-Nya bisa lihat dibawah ini ya

food.service.ts
import { Injectable } from '@angular/core';
// import foods & makanan-indo
import { Foods } from './foods';
import { MessageService } from './message.service'; 
// import rxjs observable
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class FoodService {

  private foodsUrl = 'api/lapers'; // url to web api

  httpOptions = {headers: new HttpHeaders({ 'Content-Type': 'application/json' })};

  constructor(private messageService: MessageService, private http: HttpClient) { }


   /** GET Foods from the server */
  getFoods(): Observable<Foods[]>{
    return this.http.get<Foods[]>(this.foodsUrl).pipe(tap(_ => this.log('fetched food')),
      catchError(this.handleError<Foods[]>('getFoods', []))
    );
  }

  getFood(id: number): Observable<Foods> {
    const url = `${this.foodsUrl}/${id}`;
    return this.http.get<Foods>(url).pipe(
      tap(_ => this.log(`fetched food id=${id}`)),
      catchError(this.handleError<Foods>(`getFood id=${id}`))
    );
  }

  getFoodNo404<Data>(id: number): Observable<Foods> {
    const url = `${this.foodsUrl}/?id=${id}`;
    return this.http.get<Foods[]>(url)
      .pipe(
        map(Foods => Foods[0]), // returns a {0|1} element array
        tap(h => {
          const outcome = h ? `fetched` : `did not find`;
          this.log(`${outcome} food id=${id}`);
        }),
        catchError(this.handleError<Foods>(`getFood id=${id}`))
      );
  }


  
  updateFood(laper: Foods): Observable<any> {
    return this.http.put(this.foodsUrl, laper, this.httpOptions).pipe(
       tap(_ => this.log(`update food id=${laper.id}`)), 
       catchError(this.handleError<any>('update food'))
    );
  }

  // add food
  addFood (laper: Foods): Observable<Foods> {
    return this.http.post<Foods>(this.foodsUrl, laper, this.httpOptions).pipe(tap((newFood: Foods) => this.log(`added food w/ id={newFood.id}`)), catchError(this.handleError<Foods>('addFood'))
    );
  }

  /** DELETE: delete the hero from the server */
  deleteFood (laper: Foods | number): Observable<Foods> {
    const id = typeof laper === 'number' ? laper : laper.id;
    const url = `${this.foodsUrl}/${id}`;

    return this.http.delete<Foods>(url, this.httpOptions).pipe(
      tap(_ => this.log(`deleted food id=${id}`)),
      catchError(this.handleError<Foods>('deleteFood'))
    );
  }

  // search food
  searchFoods(term: string): Observable<Foods[]> {
    if (!term.trim()) {
      return of([]);
    }

    return this.http.get<Foods[]>(`${this.foodsUrl}/?name=${term}`).pipe(
      tap(_ => this.log(`found food matching "${term}"`)),
      catchError(this.handleError<Foods[]>('searchFoods', []))
    );
  } 

  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  private log(message: string) {
    this.messageService.add(`FoodService: ${message}`);
  }
}
in-memory-data.service.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { Injectable } from '@angular/core';
import { Foods } from './foods';
@Injectable({
  providedIn: 'root'
})
export class InMemoryDataService implements InMemoryDbService {
 createDb() {
  const lapers = [
   { id: 10, name: 'nasi uduk' },
   { id: 11, name: 'nasi goreng' },
   { id: 12, name: 'semur jengkol' },
   { id: 13, name: 'soto betawi' },
   { id: 14, name: 'sop buntung' },
   { id: 15, name: 'sop iga' },
   { id: 16, name: 'bakwan' },
   { id: 17, name: 'gudeg' },
   { id: 18, name: 'mie ayam' },
   { id: 19, name: 'mie goreng' },
   { id: 20, name: 'telor dadar' }
  ];
  return {lapers};
 }

 genId(lapers: Foods[]): number {
  return lapers.length > 0 ? Math.max(...lapers.map(laper => laper.id)) + 1: 11;
 }

  constructor() { }
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FoodComponent } from './food/food.component'; 

import { FormsModule } from '@angular/forms';
import { FoodDetailComponent } from './food-detail/food-detail.component';
import { MessagesComponent } from './messages/messages.component';
import { DashboardComponent } from './dashboard/dashboard.component'; // Tambahkan forms module(1)
import { HttpClientModule } from '@angular/common/http';

import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';
import { FoodSearchComponent } from './food-search/food-search.component';
@NgModule({
  declarations: [
    AppComponent,
    FoodComponent,
    FoodDetailComponent,
    MessagesComponent,
    DashboardComponent,
    FoodSearchComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule,
    HttpClientInMemoryWebApiModule.forRoot(
      InMemoryDataService, { dataEncapsulation: false }
    )
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module.ts 
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { FoodComponent } from './food/food.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { FoodDetailComponent } from './food-detail/food-detail.component';


const routes: Routes = [
 // nama path bebas localhost:4200/food
 { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
 { path: 'dashboard', component: DashboardComponent },
 { path: 'detail/:id', component: FoodDetailComponent },
 { path: 'food', component: FoodComponent },
 
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
foods.ts
export class Foods {
 id: number;
 name: string;
}
app.component.html
<nav>
 <a routerLink="/dashboard">Dashboard</a><br>
 <a routerLink="/food">Food</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages>

FoodComponent
food.component.html
<h2>Makanan Favoritku</h2>
<!-- add form input -->
<div>
 <label>Food name:
  <input #foodName />
 </label>
 <button (click)="add(foodName.value); foodName.value=''">Add</button>
</div>
<ul class="lapers">
  <li *ngFor="let laper of lapers">
    <a routerLink="/detail/{{laper.id}}">
      <span class="badge">{{laper.id}}</span> {{laper.name}}
    </a>
    <button class="delete" title="delete laper" (click)="delete(laper)">x</button>
  </li>
</ul>
food.component.ts
import { Component, OnInit } from '@angular/core';
import { Foods } from '../foods'; // tambahkan ini import foods.ts
import { FoodService } from '../food.service';

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

 lapers: Foods[];

  constructor(private foodService: FoodService) { }

  ngOnInit() {
   this.getFoods();
  }

  getFoods(): void {
    this.foodService.getFoods().subscribe(lapers => this.lapers = lapers);
  };

  // add click eventf
  add(name: string): void {
    name = name.trim();
    if (!name) { return; }
    this.foodService.addFood({ name } as Foods).subscribe(laper => {
      this.lapers.push(laper);
    });
  }

  delete(laper: Foods): void {
    this.lapers = this.lapers.filter(h => h !== laper);
    this.foodService.deleteFood(laper).subscribe();
  }

}
FoodDetailComponent
food-detail.component.html
<div *ngIf="laper">
  <h2>{{laper.name | uppercase}} Details</h2>
  <div><span>id: </span>{{laper.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="laper.name" placeholder="name"/>
    </label>
  </div>
  <button (click)="goBack()">go back</button>
  <button (click)="save()">save</button>
</div>
food-detail.component.ts
// tambahkan INPUT
import { Component, OnInit, Input } from '@angular/core';
// Tambahkan Foods dari foods
import { Foods } from '../foods';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';

import { FoodService }  from '../food.service';

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

 @Input() laper: Foods;

   constructor(
    private route: ActivatedRoute,
    private foodService: FoodService,
    private location: Location
  ) {}

  ngOnInit(): void {
    this.getFood();
  }

  getFood(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.foodService.getFood(id).subscribe(laper => this.laper = laper);
  }

  goBack(): void {
    this.location.back();
  }

  save(): void {
    this.foodService.updateFood(this.laper).subscribe(() => this.goBack());
  }
}

DashboardComponent
dashboard.component.html
<h3>Top Foods</h3>
<div class="grid grid-pad">
  <a *ngFor="let laper of lapers" class="col-1-4"
    routerLink="/detail/{{laper.id}}">
  <div class="module laper">
    <h4>{{laper.name}}</h4>
  </div>
</a>
</div>

<app-food-search></app-food-search>
dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { Foods } from '../foods'; // tambahkan ini import foods.ts
import { FoodService } from '../food.service';

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

 lapers: Foods[] = [];

  constructor(private foodService: FoodService) { }

  ngOnInit() {
   this.getFoods();
  }

  getFoods(): void {
   this.foodService.getFoods().subscribe(lapers => this.lapers = lapers.slice(1, 5));
  }

}

FoodSearch
food-search.component.html
<div id="search-component">
 <h4><label for="search-box">Food Search</label></h4>

 <input #searchBox id="searchBox" (input)="search(searchBox.value)" />

 <ul class="search-result">
  <li *ngFor="let laper of lapers$ | async">
   <a routerLink="/detail/{{laper.id}}">
    {{laper.name}}
   </a>
  </li> 
 </ul>
</div>
food-search.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable, Subject } from 'rxjs';

import {
   debounceTime, distinctUntilChanged, switchMap
 } from 'rxjs/operators';

 import { Foods } from '../foods';
 import { FoodService } from '../food.service';

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

 lapers$: Observable<Foods[]>;
 private searchTerm = new Subject<string>();

  constructor(private foodService: FoodService) { }

  search(term: string): void {
   this.searchTerm.next(term);
  }

  ngOnInit(): void {
   this.lapers$ = this.searchTerm.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((term: string) => this.foodService.searchFoods(term)),
   );
  }

}
messagesComponent
message.component.html
<div *ngIf="messageService.messages.length">
  <h2>Messages</h2>
  <button class="clear"
          (click)="messageService.clear()">clear</button>
  <div *ngFor='let message of messageService.messages'> {{message}} </div>
</div>
message.component.ts
import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';

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

  constructor(public messageService: MessageService) { }

  ngOnInit() {
  }

}
Terimakasih sudah membaca tutorial series angular, kalau kamu mau lihat daftar tutorial nya dan source code angular dibawah ini ya
Daftar Tutorial Series Angular
Download Source code Github

1 comment:

  1. Thanks for sharing, sukses terus..
    kunjungi juga http://bit.ly/2ksPgOZ

    ReplyDelete