1

In DateRangeComponent I'm trying to emit array on button click to another (ViewerComponent) component using EventEmitter and Output decorator.

There is a getData() method in DateRangeComponent where EventEmitter emit an array from service.

@Output() dataEmitter = new EventEmitter<any[]>();

  constructor(private dataService: DataService) { }

  getData() {
    let fromDate = this.dateName[0];
    let toDate = this.dateName[1];

    this.dataService.findNameByDate(fromDate, toDate)
      .map(names => {
          this.names = names;
          this.dataEmitter.emit(this.names);
          //console.log(JSON.stringify(this.names));
        }
      )
  }

Component should receive emitted array using Input decorator:

@Input() names: any;

and there is a property binding in HTML:

<app-table *ngIf="selectedDate" [names]="names"></app-table>

but there is a problem with receiving. What's wrong?

Stackblitz

corry
  • 1,457
  • 7
  • 32
  • 63

2 Answers2

4

Your emitter is working fine. Problem is with the receiver component.

You are mixing @Input() with @Output(). You do not need to have Input() variable to receive the event emitted, you need to register the Output event instead.

Register the Output event in your receiving component as (dataEmitter)="names = $event"

<app-date-range (dataEmitter)="names = $event"></app-date-range>

And instead of decalaring name as @Input() names: any;

simply declare it as

names : Array<{}>;

Forked stackblitz

Amit Chigadani
  • 28,482
  • 13
  • 80
  • 98
  • `@Output` emit works only the first time. Is that commonly behaviour for `EventEmitter`? – corry Jun 29 '18 at 08:29
  • 1
    Whenever an event is emitted, the subscriber is triggered. You can emit it as many times as you want. But @Output event is limited to child-parent. If you want to pass it for sibling element then it has to be via the parent component. – Amit Chigadani Jun 29 '18 at 08:39
1

Several things.

Your appComponent must be like:

//app.html

    <!--we use (dataEmiter) to get the changes, and [names] to send the properties -->
    <app-date-range (dataEmitter)="emit($event)"></app-date-range>
    <app-viewer [names]="names"></app-viewer>

//And the component like
export class AppComponent  {
 names:any[]=[];  //<--declare a variable
 emit(data:any[])
 {
   this.names=data;
 }
}

In your vievewer component, not put *ngIf if app-table tag, I choose put in the div and using names.length

<div class="container">
  <div class="row" *ngIf="names.length">
    <app-table [names]="names"></app-table>
  </div>
</div>

If you want simulate a get, change the service function findByDate like

findNameByDate(fromDate: String, toDate: String) {
    return Observable.of(this.data);
  }

Of course, the date-range function must be

getData() {
    let fromDate = this.dateName[0];
    let toDate = this.dateName[1];

    this.dataService.findNameByDate(fromDate, toDate)
      .subscribe(names => {  //<---subscribe
          this.names = names;
          this.dataEmitter.emit(this.names);
          console.log(this.names);
        }
      )
  }
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • In real use case there is an Observable: `findNameByDate(fromDate: String, toDate: String): Observable { return this.http.get(`${this.api}/${fromDate}/${toDate}`) .map(res => res.json()) .catch( (error: Response) => { return Observable.throw('Cannot get data from'); } ); }` , but I didn't succeed to reproduce it on stackblitz. It throws `Unexpected token < in JSON at position 0` error – corry Jun 29 '18 at 08:37
  • 1
    @corry I told you that if you want "simulate" a "get", you can use Observable.of(...). NOTE: if you use httpClient (if not, you should be) not need map to json. If you received a "Unexpected token <" is because you are not receiving a json, else an error page or similar, you can check it if you see the response in the navigator developer tools – Eliseo Jun 29 '18 at 08:53