user351711
user351711

Reputation: 3311

Angular2 Change Detection Infinite Loop

We have a simple component with an input property as such:

<app-example [exampleInput$]="exampleInputData$"></app-example>

On the component where we use app-example we have:

get exampleInputData$(): any {
    var subject = new Subject<string>();
    console.log("Log1");

    this.exampleService.getAllData(this.id).subscribe(data => {
      console.log("Log2");
      subject.next(data);
    });

    return subject.asObservable();
  }

And the exampleService is a simple observable as such:

public getAllData(id): Observable<ExampleObject[]> {
    return this.http.get(`${this.baseUrl}data/${id}`).map((response: Response) => {
      var data = <ExampleObject[]>response.json();
      return data;
    }).catch(this.handleError);
  }

When we run this it get's into an infinite loop, if we change the changeDetection to OnPush it stops or if we remove the call to getAllData. Does anyone have an idea of why this is causing an infinite loop?

Below is the app-example component and the HTML template:

export class ExampleComponent implements OnDestroy {      
  private subscription: ISubscription;
  private parsedResponse : any;

  @Input() exampleInput$;

  getData(): void
  {    
    this.subscription = this.exampleInput$.subscribe((data) => {this.parsedResponse = data;},
      () => {
        // Here we download the data as CSV
      });
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }

Template:

<button class="btn btn-primary" (click)="getData()">
  Download As CSV
</button>

Upvotes: 4

Views: 5829

Answers (2)

Alan Grosz
Alan Grosz

Reputation: 1325

You are binding a method in the HTML. So in every change detection the method will be invoked. You need to set the observable like an attribute and the content in the exampleInputData$() put it in ngOnInit

export AppComponent {

    subject = new Subject<string>();
    observable$ = subject.asObservable();
    id: number;

    ngOnInit() {
        // I expected you know how to get the id value
        this.exampleService.getAllData(this.id).subscribe(data => {
            this.subject.next(data);
        });
    }
}

And the HTML

<app-example [exampleInput$]="observable$"></app-example>

Upvotes: 2

Chris Gomez
Chris Gomez

Reputation: 6794

I don't know how the rest of your code goes, but I think you may be calling exampleInputData$ in each render, you should do something like this:

Class Component implements OnInit {
    constructor(exampleInputDataService: ExampleInputDataService) {
    }

    ngOnInit(): void {
        this.data = this.exampleInputDataService.getData();
    }
}

Upvotes: 0

Related Questions