4

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>
2
  • Show your usage of getAllData and exampleInputData$ Commented May 23, 2018 at 15:41
  • I have added the example component and where that is used, I am not sure about getAllData as I have shown how this is used but happy to add more data if you can explain what I have missed? Commented May 23, 2018 at 15:47

2 Answers 2

2

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>
Sign up to request clarification or add additional context in comments.

1 Comment

Hi Alan, thanks for the response, do you have a simple example of what you mean? We are hoping this will be lazy-loaded and we won't actually get the data until they click the button so don't want to load all the data OnInit unless they want to export to CSV
0

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();
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.