Pada modul ini kita akan menambahkan child route untuk add dan edit recipe.
Pertama kita buat component baru, yaitu recipes/recipe-edit.component, silakan gunakan CLI atau membuatnya manual (jangan lupa untuk menambahkannya di app.modul.ts).
$ ng g c recipes/recipe-edit --skip-tests=true
Content dari component sendiri akan dibahas pada modul pembahasan Forms. Untuk saat ini hanya dibahas untuk masalah routing saja.
Buka file app-routing.module.ts, lalu tambahkan routing add dan edit recipe.
Perhatian:
- Component yang digunakan sama, yaitu recipe-edit.component
- Perhatikan juga urutan child route, pastikan new route diatas :id route, untuk mencegah error routing. (urutan route penting, karena Angular akan parse berdasarkan urutan).
Yang terjadi ketika route :id diatas new, maka ketika user request url http://localhost:4200/recipes/new, Angular akan memanggil routing :id dengan data id diisi new. Maka akan terjadi error.
import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { RecipeDetailComponent } from "./recipes/recipe-detail/recipe-detail.component"; import { RecipeEditComponent } from "./recipes/recipe-edit/recipe-edit.component"; import { RecipeHomeComponent } from "./recipes/recipe-home/recipe-home.component"; import { RecipesComponent } from "./recipes/recipes.component"; import { ShoppingListComponent } from "./shopping-list/shopping-list.component"; const appRoutes: Routes = [ {path: '', redirectTo:'/recipes', pathMatch: 'full'}, {path: 'recipes', component: RecipesComponent, children:[ {path: '', component: RecipeHomeComponent}, {path: 'new', component: RecipeEditComponent}, //child route untuk add new recipe {path: ':id', component: RecipeDetailComponent}, {path: ':id/edit', component: RecipeEditComponent} //child route untuk edit recip ]}, {path: 'shopping-list', component: ShoppingListComponent} ]; @NgModule({ imports: [RouterModule.forRoot(appRoutes)], exports: [RouterModule] }) export class AppRoutingModule{ }
Mengambil Router Parameter
Berikutnya kita akan mengambil route parameter, agar bisa ditentukan, apakah mode add atau mode edit recipe.
Buka file recipe-edit.component.ts, tambahkan code berikut.
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; @Component({ selector: 'app-recipe-edit', templateUrl: './recipe-edit.component.html', styleUrls: ['./recipe-edit.component.css'] }) export class RecipeEditComponent implements OnInit { id! : number; editMode = false; constructor(private route: ActivatedRoute) { } ngOnInit(): void { this.route.params.subscribe( (params : Params) =>{ this.id = +params['id']; this.editMode = params['id'] != null; } ); } }
Berikutnya kita akan sambungkan dengan button New Recipe dan Edit Recipe.
New Recipe
Buka file recipe-list.component.html, tambahkan event binding click, dengan method onNewRecipe().
<div class="row"> <div class="col-xs-12"> <button class="btn btn-success" (click)="onNewRecipe()">New Recipe</button> </div> </div> <hr> <div class="row"> <div class="col-xs-12"> <!-- ganti click binding menjadi property binding untuk mendapatkan index recipe item --> <app-recipe-item *ngFor="let recipeLoop of recipes; let i = index;" [recipe]="recipeLoop" [index] ="i"> </app-recipe-item> </div> </div>
Buka file recipe-list.component.ts, tambahkan method onNewRecipe() dan inject route instance untuk mengakses route dan activated route untuk dapat menggunakan relative path.
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Recipe } from '../recipe.model'; import { RecipeService } from '../recipe.service'; // RecipeService @Component({ selector: 'app-recipe-list', templateUrl: './recipe-list.component.html', styleUrls: ['./recipe-list.component.css'] }) export class RecipeListComponent implements OnInit { recipes!: Recipe[]; //tambahkan Router dan ActivatedRoute constructor(private recipeService: RecipeService, private router: Router, private route: ActivatedRoute ) { } ngOnInit(): void { this.recipes = this.recipeService.getRecipes(); } // method yang di trigger saat New Recipe button di click. onNewRecipe(){ this.router.navigate(['new'], {relativeTo: this.route}); } }
Edit Recipe
Untuk edit recipe, buka file recipe-detail.component.html, tambahkan event binding click dengan method onRecipeEdit.
<div class="row"> <div class="col-xs-12"> <img [src]="recipe.imgPath" alt="{{recipe.name}}" class="img-fluid" style="max-height:240px;"> </div> </div> <div class="row"> <div class="col-xs-12"> <h1>{{recipe.name}}</h1> </div> </div> <div class="row"> <div class="col-xs-12"> <div class="dropdown" appDropDown> <a class="btn btn-primary dropdown-toggle" role="button" data-toggle="dropdown">Manage Recipe</a> <div class="dropdown-menu"> <a class="dropdown-item" (click)="onAddShoppingList()" style="cursor:pointer;">Add Shopping List</a> <a class="dropdown-item" style="cursor:pointer;" (click)="onEditRecipe()">Edit Recipe</a> <a class="dropdown-item" style="cursor:pointer;">Delete Recipe</a> </div> </div> </div> </div> <div class="row"> <div class="col-xs-12">{{recipe.description}}</div> </div> <div class="row"> <div class="col-xs-12"> <ul class="list-group"> <li class="list-group-item" *ngFor="let ingredient of recipe.ingredients"> {{ingredient.name}} - {{ingredient.amount}} </li> </ul> </div> </div>
Buka file recipe-detail.component.ts, tambahkan method onRecipeEdit untuk melakukan navigasi ke recipe-edit.component.ts dengan edit mode.
import { Component, OnInit} from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { Recipe } from '../recipe.model'; import { RecipeService } from '../recipe.service'; @Component({ selector: 'app-recipe-detail', templateUrl: './recipe-detail.component.html', styleUrls: ['./recipe-detail.component.css'] }) export class RecipeDetailComponent implements OnInit { recipe! : Recipe; id! : number; //tambahkan akses ke router instance constructor(private recipeServ : RecipeService, private route: ActivatedRoute, private router: Router ) { } ngOnInit(): void { this.route.params.subscribe( (params: Params) =>{ this.id = +params['id']; this.recipe = this.recipeServ.getRecipe(this.id); } ); } onAddShoppingList(){ this.recipeServ.addIngToShopList(this.recipe.ingredients); } //navigasi ke recipe-edit dengan edit mode onEditRecipe(){ this.router.navigate(['edit'], {relativeTo: this.route}); } }
Tips
Anda juga bisa melakukan navigasi yang lebih rumit. Contoh code ini adalah alternative jika suatu saat dibutuhkan.
this.router.navigate(['../', this.id, 'edit'], {relativeTo: this.route} );
Sesuai ekpektasi, routing untuk Add dan Edit Recipe sudah berhasil ditambahkan. Button New dan Edit Recipe juga sudah berfungsi.
Sampai disini kita sudah berhasil menambahkan child route. Pada modul berikutnya kita akan membahas Observable.