Menguasai Komunikasi Antar Komponen Angular: Auto Cuan Pake `@Input()` dan `@Output()` Gaes!

Komunikasi Komponen Angular: Input & Output Properties Mudah Dipahami

PPLG

PPLG

Penulis

11 Jun 2026
26 x dilihat

Oke, gaes! Pernah gak sih pas lagi nge-dev aplikasi Angular, kalian ngerasa komponen-komponennya itu kayak pulau-pulau terpisah? Masing-masing punya tugas sendiri, tapi kok ya susah banget ngobrol satu sama lain? Nah, vibes-nya emang gitu awalnya! Tapi jangan khawatir, karena hari ini kita bakal spill tuntas gimana caranya bikin komponen-komponen kalian auto connect dan ngobrol lancar jaya kayak lagi nongkrong bareng. Kuncinya? Dua properti sakti mandraguna: @Input() dan @Output(). Gaspol!

Konsep Inti: Kenapa Komponen Perlu Ngobrol?

Di dunia Angular yang penuh dengan komponen, sering banget kita butuh komponen parent (induk) ngasih data ke komponen child (anak), atau sebaliknya, komponen child ngasih tahu ke parent kalau ada sesuatu yang terjadi. Ini penting banget biar aplikasi kita rapi, reusable, dan gampang di-maintain. Bayangin aja kalau semua logika ada di satu komponen, auto pusing, ngab!

1. Ketika Parent Curhat ke Child: Si @Input() Auto Siap Dengar!

  • Fungsinya apa sih? @Input() itu kayak pintu masuk data dari luar. Jadi, komponen parent bisa "ngirim" data ke komponen child lewat properti yang di-declare sebagai @Input() ini. Arahnya selalu dari parent ke child. Simpelnya, parent kasih informasi, child terima dan pake.
  • Gimana Cara Kerjanya? Kalian declare properti di komponen child pake decorator @Input(). Nah, di template parent, kalian tinggal binding properti itu ke data yang mau dikirim. Auto jadi deh!

2. Ketika Child Ngasih Info ke Parent: @Output() Auto Lapor, Boss!

  • Fungsinya apa sih? Nah, kebalikannya nih. Kadang komponen child ngelakuin sesuatu (misalnya: tombol diklik, form disubmit), dan si parent perlu tahu kejadian itu. Di sinilah @Output() berperan! @Output() memungkinkan komponen child "mengeluarkan" atau "mengirimkan" event custom ke parent. Arahnya selalu dari child ke parent.
  • Gimana Cara Kerjanya? Kalian declare properti di komponen child pake decorator @Output(), tapi propertinya harus bertipe EventEmitter<T>. Terus, kalau ada event di child (misalnya (click)), kalian panggil method .emit() dari EventEmitter itu buat ngirim data atau sinyal ke parent. Di template parent, kalian tinggal "dengar" event custom ini dan tangkap datanya. Mantul kan?

Langkah-langkah Praktis/Tutorial: Bikin Aplikasi Product Card Minimalis!

Yuk, biar afdol, kita bikin contoh sederhana. Kita punya komponen AppComponent (parent) yang akan menampilkan daftar produk, dan tiap produk akan ditampilkan oleh komponen ProductCardComponent (child). Child bakal nerima data produk dan ngasih tahu parent kalo tombol "Add to Cart" di klik.

1. Siapkan Proyek Angularmu (Kalo Belum Ada)

ng new product-app --no-standalone
cd product-app

2. Bikin Komponen Child: ProductCardComponent

ng g c product-card
  • product-card.component.ts (Child):

    import { Component, Input, Output, EventEmitter } from '@angular/core';
    
    // Definisikan interface untuk produk kita biar type-safe, gaes!
    interface Product {
      id: number;
      name: string;
      price: number;
      imageUrl: string;
    }
    
    @Component({
      selector: 'app-product-card',
      templateUrl: './product-card.component.html',
      styleUrls: ['./product-card.component.css']
    })
    export class ProductCardComponent {
      // @Input(): Menerima data produk dari parent
      // Tanda '!' berarti kita yakin properti ini akan di-assign oleh parent
      @Input() product!: Product; 
    
      // @Output(): Mengeluarkan event ketika tombol "Add to Cart" di klik
      // EventEmitter<number> artinya event ini akan mengirim data bertipe number (ID produk)
      @Output() addToCart = new EventEmitter<number>();
    
      // Method ini dipanggil ketika tombol di klik
      onAddToCartClick(): void {
        this.addToCart.emit(this.product.id); // Ngirim ID produk ke parent
        console.log(`Produk '${this.product.name}' dengan ID ${this.product.id} ditambahkan ke keranjang! (ini dari child)`);
      }
    }
    
  • product-card.component.html (Child):

    <div class="product-card">
      <img [src]="product.imageUrl" alt="{{ product.name }}" class="product-image">
      <h3 class="product-name">{{ product.name }}</h3>
      <p class="product-price">Rp {{ product.price | number:'1.0-0' }}</p>
      <button (click)="onAddToCartClick()" class="add-to-cart-button">Tambah ke Keranjang</button>
    </div>
    
  • product-card.component.css (Child):

    .product-card {
      border: 1px solid #e0e0e0;
      border-radius: 8px;
      padding: 15px;
      margin: 10px;
      width: 250px;
      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
      display: inline-block;
      text-align: center;
      transition: transform 0.2s ease-in-out;
    }
    
    .product-card:hover {
      transform: translateY(-5px);
    }
    
    .product-image {
      max-width: 100%;
      height: 180px;
      object-fit: contain;
      margin-bottom: 10px;
      border-radius: 4px;
    }
    
    .product-name {
      font-size: 1.2em;
      margin: 10px 0;
      color: #333;
    }
    
    .product-price {
      font-size: 1.1em;
      color: #007bff;
      font-weight: bold;
      margin-bottom: 15px;
    }
    
    .add-to-cart-button {
      background-color: #28a745;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      cursor: pointer;
      font-size: 1em;
      transition: background-color 0.2s ease-in-out;
    }
    
    .add-to-cart-button:hover {
      background-color: #218838;
    }
    

3. Komponen Parent: AppComponent

  • app.component.ts (Parent):

    import { Component } from '@angular/core';
    
    interface Product {
      id: number;
      name: string;
      price: number;
      imageUrl: string;
    }
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'product-app';
    
      // Data produk yang akan dikirim ke komponen child
      products: Product[] = [
        { id: 1, name: 'Smartwatch Keren 2024', price: 1500000, imageUrl: 'https://images.unsplash.com/photo-1546868871-7041f2a55e12?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8c21hcnR3YXRjaHx8fHx8fDE3MTk3NDU2Mjg&ixlib=rb-4.0.3&q=80&w=400' },
        { id: 2, name: 'Headphone Gaming RGB', price: 999000, imageUrl: 'https://images.unsplash.com/photo-1546435345-0d0246231d68?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8aGVhZHBob25lfHx8fHx8MTcxOTc0NTY0Mg&ixlib=rb-4.0.3&q=80&w=400' },
        { id: 3, name: 'Keyboard Mekanik Pro', price: 1200000, imageUrl: 'https://images.unsplash.com/photo-1627993356066-6b2c2d4e7d9b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb29tfHx8a2V5Ym9hcmR8fHx8fHwxNzE5NzQ1NjU3&ixlib=rb-4.0.3&q=80&w=400' },
      ];
    
      // Method ini dipanggil ketika event 'addToCart' dari child diterima
      handleAddToCart(productId: number): void {
        console.log(`Event 'addToCart' diterima dari child untuk Product ID: ${productId}`);
        const addedProduct = this.products.find(p => p.id === productId);
        if (addedProduct) {
          alert(`Yeay! ${addedProduct.name} berhasil ditambahkan ke keranjang! (ini dari parent)`);
          // Di sini kamu bisa tambahin logika lain, misalnya update state keranjang belanja
        }
      }
    }
    
  • app.component.html (Parent):

    <div class="container">
      <h1>Daftar Produk Keren Kita!</h1>
      <div class="product-list-wrapper">
        <!-- Loop melalui array products dan render ProductCardComponent untuk setiap produk -->
        <!-- [product]="p" -> ini properti binding, ngirim data 'p' ke @Input() 'product' di child -->
        <!-- (addToCart)="handleAddToCart($event)" -> ini event binding, mendengarkan @Output() 'addToCart' dari child -->
        <!-- $event adalah data yang di-emit oleh child (dalam kasus ini, product.id) -->
        <app-product-card
          *ngFor="let p of products"
          [product]="p"
          (addToCart)="handleAddToCart($event)"
        ></app-product-card>
      </div>
    </div>
    
  • app.component.css (Parent):

    .container {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      text-align: center;
      padding: 20px;
      background-color: #f8f9fa;
      min-height: 100vh;
    }
    
    h1 {
      color: #343a40;
      margin-bottom: 30px;
    }
    
    .product-list-wrapper {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 20px; /* Memberikan jarak antar card */
    }
    

4. Jangan Lupa AppModule!

Pastikan ProductCardComponent sudah di-import dan di-declare di AppModule kalau kamu bikin proyek tanpa standalone.

  • app.module.ts:
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    
    import { AppComponent } from './app.component';
    import { ProductCardComponent } from './product-card/product-card.component'; // Import komponen child
    
    @NgModule({
      declarations: [
        AppComponent,
        ProductCardComponent // Tambahkan di declarations
      ],
      imports: [
        BrowserModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

5. Gaspol! Jalankan Aplikasimu

ng serve -o

Lihat di browser, kamu akan melihat daftar produk. Coba klik tombol "Tambah ke Keranjang", dan lihat console browser serta alert yang muncul! Itu tandanya komunikasi antar komponen kalian sudah jalan, gaes!

Tips Praktis Biar Makin Ciamik!

  • Alias @Input() dan @Output(): Bikin Nama Properti Beda! Kadang, kalian pengen nama properti di template parent beda sama nama properti di komponen child. Auto bisa!

    // Di child component.ts
    @Input('itemData') product!: Product; // Sekarang di parent pake [itemData]="..."
    @Output('itemAdded') addToCart = new EventEmitter<number>(); // Di parent pake (itemAdded)="..."
    

    Ini berguna banget kalo kalian pengen properti product di child tetap pake nama product tapi di parent pengen lebih generik itemData, misalnya.

  • Nilai Default buat @Input(): Biar Gak Undefined! Kalo kalian yakin @Input() kadang gak di-set oleh parent, kasih aja nilai default biar aman!

    @Input() title: string = 'Judul Default';
    

    Atau, kalo pakai strict mode dan properti wajib diisi, jangan lupa tanda ! setelah nama properti, atau inisialisasi di constructor.

  • Pake Interface atau Type: Auto Type-Safe! Kayak contoh di atas, selalu define interface atau type untuk data yang kalian kirim. Ini bikin kode kalian lebih robust, gampang di-debug, dan IDE auto ngasih saran. Auto pro, ngab!

  • ngOnChanges: Ngelihat Perubahan @Input()! Kalo kalian perlu ngelakuin sesuatu setiap kali nilai @Input() berubah (misalnya, update UI atau panggil API), bisa pake lifecycle hook ngOnChanges. Ini super power banget buat merespons perubahan data dari parent.

    import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
    
    @Component({ /* ... */ })
    export class ProductCardComponent implements OnChanges { // Implement OnChanges
      @Input() product!: Product;
    
      ngOnChanges(changes: SimpleChanges): void {
        if (changes['product']) {
          console.log('Data produk berubah nih, gaes!', changes['product'].currentValue);
          // Lakukan sesuatu dengan perubahan data produk
        }
      }
    }
    
  • Ngebatesin Emit Event: Biar Gak Spam! Kalo event di-emit terlalu sering (misalnya dari (keyup)), bisa jadi masalah performa. Pake debounceTime dari RxJS biar event-nya di-emit setelah ada jeda waktu tertentu. Ini best practice banget, lho!

Kesimpulan:

Gimana, gaes? Udah mulai kerasa kan "power"-nya @Input() dan @Output() buat bikin aplikasi Angular kalian makin interaktif dan terstruktur? Dua properti ini adalah fondasi utama komunikasi antar komponen di Angular. Dengan menguasainya, kalian bisa bangun aplikasi yang lebih modular, reusable, dan gampang dikelola. Jadi, jangan cuma jago ngoding, tapi juga jago bikin komponen-komponennya bisa ngobrol asik! Keep ngulik, keep nge-dev, dan terus bikin aplikasi yang bikin ngiler! Gas!


0.0

Berikan Rating

Komentar (0)

Silakan login untuk memberikan komentar.

Login Sekarang

Belum ada komentar. Jadilah yang pertama!

Menyukai Artikel (0)

Belum ada siswa yang menyukai artikel ini.

Pembaca (0)

Belum ada user yang membaca artikel ini.