Search code examples
angularangular2-servicesangular2-componentsangular2-observables

Angular2 component doesn't update when data becomes available


I have a component with attributes bound to a data property.

@Component({
 encapsulation: ViewEncapsulation.None,
 selector: 'animal-detail-main',
 styleUrls: ['animal-detail-main.component.scss'],
 template: `
      <div>
        {{data | json}}
      </div>
      `
})

export class DetailMain  {
  data: any;

 private dataSvc: MainService;

 constructor( 
    @Inject(MainService)  dataSvc: MainService,
    ) {
      this.dataSvc = dataSvc;
    }

  ngOnInit() {
        var fetchedData: any;

        this.dataSvc.currentID$
           .subscribe(
              currentID => {
                   currentID = currentID;
                   this.dataSvc
                     .getDetail(currentID)
                     .map(response => response.json())
                     .subscribe (
                         data => {fetchedData = data[0]},
                          err => console.log('Error',err),
                          () => {
                          console.log('fetchedData',fetchedData);
                          setTimeout(() => {
                             this.data = fetchedData;
                             console.log("this.data",this.data);
                          }, 2000);
                    }
           );
      });   
 }
}

Basically the currentID$ service holds an ID for the current object, so that's fetched back into currentID, and then currentID is passed into the getDetail service to return the entire object for that ID.

Without the setTimeout, the function returns the object data late and it never gets assigned to this.data.

With the setTimeout, the console.log right after this.data is assigned the fetchData returned object correctly logs the returned object, but the view never updates so the data isn't displayed in the component.

I expected that the component would auto-magically refresh once the data became available, but it doesn't, and I don't know how to trigger an update of the view.


Solution

  • I think you might want to use flatMap here to chain the requests, as the second one is dependent on the Observable from your service. EDIT. This works well if your id is a BehaviorSubject.

    constructor(private dataSvc: MainService) { }
    
    data: any = {}; // if it's an object
    
    ngOnInit() {
       this.dataSvc.currentID$
         .flatMap(currentId => this.dataSvc.getDetail(currentId))
            .map(res => res.json()) // could do the mapping in the service
            .subscribe(data => {
               this.data = data[0];
            });
    }
    

    About the view not updating, not being entirely sure about that.... Try the above solution, if the template is not updated, you could try and trigger the change detection manually with ChangeDetectorRef, but I don't really see why the change detection wouldn't happen. But these things just seem to happen sometimes :)