Saya sangat baru di Angular 2 dan saya ragu tentang cara kerja penggunaan komunikasi lintas komponen ini menggunakan layanan.

Dalam aplikasi saya, saya memiliki kelas layanan RecipeService ini:

@Injectable()
export class RecipeService {

  // Hold a Recipe object to be emitted to another component to implement cross component comunication:
  recipeSelected = new EventEmitter<Recipe>();

  // List of all recipes (maybe later can be obtained by a web service)
  private recipes: Recipe[] = [
    new Recipe(
      'Tasty Schnitzel',
      'A super-tasty Schnitzel - just awesome!',
      'https://upload.wikimedia.org/wikipedia/commons/7/72/Schnitzel.JPG',
      [
        new Ingredient('Meat', 1),
        new Ingredient('French Fries', 20)
      ]),
    new Recipe('Big Fat Burger',
      'What else you need to say?',
      'https://upload.wikimedia.org/wikipedia/commons/b/be/Burger_King_Angus_Bacon_%26_Cheese_Steak_Burger.jpg',
      [
        new Ingredient('Buns', 2),
        new Ingredient('Meat', 1)
      ])
  ];

  // Inject a sub service:
  constructor(private slService: ShoppingListService) {}

  /**
   * Return a copy of the reipes array.
   * @returns {Recipe[]}
   */
  getRecipes() {
    return this.recipes.slice();
  }

  addIngredientsToShoppingList(ingredients: Ingredient[]) {
    this.slService.addIngredients(ingredients);
  }
}

Kelas ini digunakan oleh 2 komponen berbeda untuk mengimplementasikan komunikasi lintas komponen oleh emitor ini:

recipeSelected = new EventEmitter<Recipe>();

Dari apa yang saya pahami (koreksi saya jika saya melakukan pernyataan yang salah) recipeSelected ini memancarkan acara yang menyimpan informasi yang terkandung ke dalam objek Recipe (ini berisi beberapa bidang string).

Lalu saya memiliki komponen RecipeItemComponent ini (ini mewakili resep dan tampilannya menunjukkan informasi terkait resep tertentu):

@Component({
  selector: 'app-recipe-item',
  templateUrl: './recipe-item.component.html',
  styleUrls: ['./recipe-item.component.css']
})
export class RecipeItemComponent implements OnInit {
  @Input() recipe: Recipe;

  // Inkect the RecipeService to use it in this component:
  constructor(private recipeService: RecipeService) { }

  ngOnInit() {
  }

  /**
   * When a specific recipe is selected in the page it emit the selected recipe to comunicate
   * with another component
   */
  onSelected() {
    this.recipeService.recipeSelected.emit(this.recipe);
  }

}

Saat pengguna mengeklik tautan ke tampilan yang terkait dengan RecipeItemComponent ini, metode onSelected() dari kelas ini dijalankan.

Dari apa yang saya tahu itu hanya memancarkan acara yang terkait dengan objek Resep ini. Jadi saya pikir itu adalah menembak ke orang lain konten objek ini, di mana orang lain harus menjadi komponen lain (sehingga diimplementasikan konsep komunikasi lintas komponen).

Lalu saya memiliki kelas komponen RecipesComponent lainnya ini:

@Component({
  selector: 'app-recipes',
  templateUrl: './recipes.component.html',
  styleUrls: ['./recipes.component.css'],
  providers: [RecipeService]
})
export class RecipesComponent implements OnInit {
  selectedRecipe: Recipe;

  /**
   * Inject the RecupeService to use it in this component
   * @param recipeService
   */
  constructor(private recipeService: RecipeService) { }

  /**
   * Subscribe on the event emitted when a recipe is selected:
   */
  ngOnInit() {
    this.recipeService.recipeSelected
      .subscribe(
        (recipe: Recipe) => {
          this.selectedRecipe = recipe;
        }
      );
  }

}

Dari apa yang saya pahami, saya mendaftarkan "pendengar" (apakah pendengar?) untuk acara semacam ini ke dalam metode ngOnInit(), dengan:

  ngOnInit() {
    this.recipeService.recipeSelected
      .subscribe(
        (recipe: Recipe) => {
          this.selectedRecipe = recipe;
        }
      );
  }

Jadi, dalam praktiknya, setiap kali komponen RecipeItemComponent memancarkan peristiwa yang berisi objek Recipe, informasi ini diterima oleh komponen RecipesComponent yang menggunakan dia. Apakah itu?

Lalu saya ragu tentang sintaks ini:

(recipe: Recipe) => {
    this.selectedRecipe = recipe;
}

Apa sebenarnya artinya? Menurut saya resep: Resep adalah konten acara yang diterima. Ini seperti cara implisit untuk mendeklarasikan suatu fungsi? (Saya berasal dari Java dan saya tidak begitu menyukai sintaksis semacam ini).

Keraguan lainnya adalah: mengapa kode ini dideklarasikan ke dalam ngOnInit()? Ide saya adalah begitu mendeklarasikan pendengar ketika komponen ini dibuat dan kemudian pendengar ini bereaksi terhadap peristiwa yang bisa datang untuk kedua kalinya. Apakah itu?

1
AndreaNobili 9 Agustus 2017, 18:30

2 jawaban

Jawaban Terbaik

EventEmitter seharusnya tidak digunakan dalam layanan.

Lihat postingan ini: Apa penggunaan yang tepat dari EventEmitter?

Dari postingan itu:

Use by directives and components to emit custom Events.

Tidak untuk digunakan dalam layanan. Seperti yang disebutkan @Pablo, bahkan untuk komponen disarankan agar Anda menggunakan @Output untuk mengekspos acara Anda.

Untuk layanan, biasanya deteksi perubahan Angular akan menangani perubahan pada data layanan. Jadi yang perlu Anda lakukan adalah mengekspos data itu. Saya punya contoh di sini:

https://blogs.msmvps.com/deborahk/build-a-simple-angular-service-to-share-data/

Dan plunker yang sesuai di sini: https://plnkr.co/edit/KT4JLmpcwGBM2xdZQeI9?p=preview< /a>

import { Injectable } from '@angular/core';

@Injectable() 
export class DataService {
  serviceData: string; 
}

Jadi ini:

@Injectable()
export class RecipeService {

  recipeSelected = new EventEmitter<Recipe>();

Menjadi ini:

@Injectable()
export class RecipeService {

  recipeSelected: Recipe;

Dan ini:

  onSelected() {
    this.recipeService.recipeSelected.emit(this.recipe);
  }

Menjadi ini:

  onSelected() {
    this.recipeService.recipeSelected=this.recipe;
  }

Dan ini:

export class RecipesComponent implements OnInit {
  selectedRecipe: Recipe;

  ngOnInit() {
    this.recipeService.recipeSelected
      .subscribe(
        (recipe: Recipe) => {
          this.selectedRecipe = recipe;
        }
      );
  }

}

Menjadi ini:

export class RecipesComponent implements OnInit {
  get selectedRecipe(): Recipe {
     return this.recipeService.recipeSelected;
  };   
}

Setiap kali recipeSelected berubah, deteksi perubahan Angular akan diberitahukan dan UI akan di-rebind ke nilai selectedRecipe saat ini.

2
DeborahK 9 Agustus 2017, 20:22

Saya pikir Anda telah memahami deskripsi potongan kode itu. Saya pikir saya tidak akan menggunakan layanan untuk memancarkan resep, tetapi hanya atribut @Output, tetapi bagaimanapun analisis Anda benar.

Tentang notasi panah, saya sarankan Anda untuk membaca MDN dokumentasi.

Dan tentang ngOnInit(): Biasanya di Angular konstruktor digunakan untuk menyuntikkan dependensi saja, karena logika inisialisasi utama diatur dalam metode ngOnInit hanya karena semua atribut yang didekorasi dengan @Input diinisialisasi tepat sebelum memanggil metode ini, jadi "konstruksi" visual komponen tidak akan selesai sebelum metode ini dipanggil.

1
Pablo Lozano 9 Agustus 2017, 16:01