0

I have a service where I fetch some data form Firebase. That service offers an observable, which I then subscribe to in my component class. When the data is loaded, and sent to the array, the DOM updates with new data, but I need to run some javascript and jQuery code again after the DOM update which I can't figure out how to.

My service method looks like this:

getSubjects() {
    return new Observable(observer => {
      this.subjectsRef.orderByChild('name').on("value", snapshot => {
        var tempArr = [];
        snapshot.forEach(function(data) {
          var subject = {
            name: data.val().name,
            imgUrl: data.val().imgUrl,
            description: data.val().description,
            teachers: data.val().teachers
          }
          tempArr.push(subject);
        });
        observer.next(tempArr);
      });
    // this.broadcastUpdate();
  });
  }

And my component:

export class SubjectsCmp implements AfterViewInit, OnInit, OnChanges {

  constructor(
    private _subjectsService: SubjectsService
  ) {
  }

  ngOnInit() {
    this._subjectsService.getSubjects().subscribe( subjects => this.subjects = subjects);
  }
}

I've looked a bit at the documentation for RxJS but to no avail. I thought I could rewrite it to follow the example they give::

var subscription = source.subscribe(
  function (x) {
    console.log('Next: %s', x);
  },
  function (err) {
    console.log('Error: %s', err);
  },
  function () {
    console.log('Completed');
  });

But 'Completed' never fires.

Angular 2's onChanges observer only responds to changes caused by input events, so that won't work either. Basically I just need to run a method after the array is populated, I'm thinking I'm missing something obvious?

Chris
  • 7,830
  • 6
  • 38
  • 72
  • You need to run something after Angular's change detection updates the DOM? If so, try calling setTimeout() after you update `this.subjects`. Do your additional work in the setTimeout() callback function. – Mark Rajcok Jan 08 '16 at 17:23
  • Could you provide an example @MarkRajcok. Also, will this fire every time the data is updated or only once? – Chris Jan 08 '16 at 17:35
  • `ngOnInit() { this._subjectsService.getSubjects().subscribe( subjects => { this.subjects = subjects; setTimeout(function() { ...run your stuff here... }, 0); } ); }`. It will fire whenever your observable has something new to send. – Mark Rajcok Jan 08 '16 at 18:10
  • @MarkRajcok for some reason it fires before the data is loaded and is sent. Putting a log statement in the timeout function and one in the service, the log in the service prints before the timeout – Chris Jan 08 '16 at 18:45
  • That sounds like it is working as I expected... you request data from your service, then sometime later the data comes in and the observable notifies any subscribers. The one subscriber updates the component's `subject` property, and then uses `setTimeout()` to give Angular a chance to run change detection and update the DOM. Then your setTimeout callback function is called/executed. – Mark Rajcok Jan 08 '16 at 19:32
  • @MarkRajcok sorry, I meant it the other way around. The timeout fires before the service – Chris Jan 11 '16 at 10:22
  • Is that because of some initial subscription notification? If so, in the setTimeout callback, just handle the case where `this.subjects` is empty. – Mark Rajcok Jan 11 '16 at 15:57
  • I don't know if I am using the Observer class in the wrong way? – Chris Jan 12 '16 at 08:40

1 Answers1

1

subscribe() method returns Subscriber, which inherits add() method that you can use:

ngOnInit() {
  this._subjectsService.getSubjects()
    .subscribe( subjects => this.subjects = subjects)
    // add new subscription
    .add(() => console.log('Completed', this.subjects));
}
Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • This doesn't work. It never fires. I'm starting to suspect something is wrong with the way I'm using my observable? – Chris Jan 12 '16 at 08:44
  • Make sure you're [importing the operators](http://stackoverflow.com/a/34581771/1876949). I'd also suggest you look into [generating observables](http://reactivex.io/documentation/operators.html#categorized) and avoid `new Observable()` if you're just starting with them... – Sasxa Jan 12 '16 at 09:43