javascript - Angular 2 hur man skickar en funktion med parametrar till en barnkomponent?


Hur skickar man korrekt en funktion från en föräldrakomponent till en barnkomponent när funktionen tar parametrar?

I ngOnInit, hur man skapar omfattningen för en funktion som:

addToList(id) {
  this.store.dispatch(this.listActions.addToList(id));
}

ngOnInit, vilket är fel just nu.

ngOnInit() {
  this.addToList = this.addToList.bind(this, id);
}

I min föräldrakomponent har jag funktionen addToCart(id).

Jag vill skicka den funktionen till min barnkomponent, som har en lista med objekt, och när jag klickar på LÄGG TILL-knappen på ett objekt, vill jag anropa addToCart(item_id) till föräldern.

Svar #1

@Maareks svar är ett bra svar, och är förmodligen det 'rätta' sättet att göra det på. Vad jag presenterar här är ett enklare sätt att kommunicera specifikt från Barnet till Föräldern.

Det du föreslog i det ursprungliga inlägget var att låta Föräldern skicka en callback-metod till Barnet, så att Barnet kan anropa den med data när det är lämpligt. För att utföra denna specifika uppgift (data från Barn till Förälder vid någon handling i Barnet) är det lämpligt att använda Events, med hjälp av EventEmitter inifrån Barnet. Se denna API-referens som har ett exempel: https://angular.io/docs/ts/latest/api/core/index/EventEmitter-class.html och denna Plunker jag skapade som en demo: https://embed.plnkr.co/T1wFqVOhMXgX6NRfTuiC/

I barnet har du kod som detta:

import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
  selector: 'item',
  template: `
    <div class="item">
      <button type="button" (click)="addItem()">Add</button>
      <p>{{id}}
    </div>
  `
})
export class ItemComponent {
  @Input() id: string;
  //key line here: this emitter can be bound to by parent to get notifications
  @Output() add: EventEmitter<string> = new EventEmitter<string>();

  constructor() { }

  addItem() {
    //then when the button is clicked, emit events to the parent.
    this.add.emit(this.id);
  }
}

Föräldern skulle kalla på att skapa komponenten så här:

<item id="1" (add)="addToList($event)"></item> Där addToList() är en funktion på föräldern som utför det arbete som din callback var tänkt att göra. $event är data som skickas från barnet (id:t).

Svar #2

Det finns inte mycket detaljer här, men utifrån vad jag samlar ihop tror jag att det du vill ha är en injicerbar tjänst (demonstrerad här: https://angular.io/docs/ts/latest/tutorial/toh-pt4.html) för att hantera de dataobjekt som delas mellan komponenterna. Istället för att skriva en massa kod här (vilket visas bättre på den sidan i handledningen) kommer jag att beskriva vad jag tror att du försöker göra och hur jag skulle gå tillväga för att göra det.

Hela butikens datamodell kan hanteras via en tjänst (kanske store.service.ts). Den kommer att ha dina CRUD-funktioner exponerade för de olika egenskaperna i butikens modell. Listan som du lägger till här bör ha en publik getter som returnerar ett observabelt värde av listan i tjänsten samt en publik funktion för att lägga till och ta bort från listan. Något i stil med detta:

@Injectable
export class StoreService {
  private _storeList:BehaviorSubject<Array<any>> = new BehaviorSubject<Array<any>>([]);

  /*I'm sure the store has other properties, set them up here. I'd suggest
    breaking any arrays out of the general object (unless you want to use
    pipes which are awesome but keeping it simple here) but if the store has
    a lot of general properties (name, address, whatever) they can be stored 
    in a single BehaviorSubject of type any.
  */

  constructor(){}

  get StoreList() { return this._storeList.asObservable() }

  public addToList(id) {
      let curVal = this._storeList.getValue();
      curVal.push(id);
      this._storeList.next(curVal);
  }

}

Du skulle då injicera denna tjänst i konstruktorn för både föräldern och barnet constructor(private _storeService:StoreService){} (och alla andra komponenter som behöver den). Barnet skulle då kunna prenumerera på listan: get List() { return this._storeService.StoreList } och föräldern kan kalla på add-funktionen för att lägga till i listan. En sak att notera, när du lägger detta till i din mall som en *ngFor, se till att skicka värdet genom async-pipen. *ngFor="List | async" annars kan du riva ditt hår medan du försöker lista ut varför du får fel.

Den här artikeln hjälpte mig mycket med detta också (även om jag kanske skulle föreslå att undvika immutable i början tills du är helt bekväm med Angular 2): http://blog.angular-university.io/how-to-build-angular2-apps-using-rxjs-observable-data-services-pitfalls-to-avoid/