robert
robert

Reputation: 857

Problems with updating the view..when using service to service call

I use the app service to listen for pouchdb changes:

init() {
    const pouch = new PouchDB('app_data', {});
    const remoteDB = new PouchDB('http://xx.xx.xx.xx:35986/app_data', {
        skip_setup: true,
        auto_compaction: true,
        auth: {
          username: 'root',
          password: 'root'
        }
      });
    const sync = pouch.sync(remoteDB, {
      live: true,
      retry: true
    }).on('change', (info) => {
      this.facilityProtoService.update();
...

and another service to send data to the view:

@Injectable()
export class FacilityProtoService {

  constructor() {}

  private pouch = new PouchDB('app_data', {});
  private facilityProtoStore = new Subject<any>();
  public facilityProto$ = this.facilityProtoStore.asObservable();

  public update() {
    console.log('[facilityProto] update');
    this.pouch.get('facilities')
      .then((res:any) => this.facilityProtoStore.next(res.structure))
  }
}

component looks like:

@Component({
  selector: 'zpa-facility-designer',
  template: `
    <p>facility-designer works!</p>
    <ng-container *ngFor="let key of test$ | async, trackBy: trackByFn">
      {{ key }}<br>
    </ng-container>
  `
})
export class FacilityDesignerComponent implements OnInit {

  test$: any;

  constructor(
    private facilityProtoService: FacilityProtoService
  ) {}

  ngOnInit() {
    this.test$ =  this.facilityProtoService.facilityProto$.pipe(tap(i => console.log(Object.keys(i))), map(i => Object.keys(i)))
  }

  trackByFn(index, item) {
    return index;
  }

}

The data is always shown correctly in tap operator, but view did not update.

As soon as I add an interval function to the constructor of the app service all works perfectly, the view updates correctly.

constructor(
    private facilityProtoService: FacilityProtoService
  ) {
    console.log('app service');
    setInterval(() => {}, 1000);
  }

Both services are singletons and the app service init is triggered by app_initializer.

Any ideas why it works with interval? And only in component and not in the component view?

Edit: It also works when the interval function is in the ngOnInit hook of the component.

Edit 2:

I have make the example much smaller:

init() {
    this.changes.next(5);
    setTimeout(() => {
      this.changes.next(6)
    });
    this.pouch = new PouchDB('app', {});
    const remoteDB = new PouchDB('http://127.0.0.1:5984/app', {
      skip_setup: true,
      auth: {
        username: 'root',
        password: 'root'
      }
    });
    const sync = this.pouch
        .sync(remoteDB, {
          live: true,
          retry: true
        })
        .on('change', () => {
          this.changes.next(7)
        })
  }

value 5 and 6 are correctly displayed in view... 7 only in component.

Upvotes: 0

Views: 67

Answers (2)

Ivan Mihaylov
Ivan Mihaylov

Reputation: 433

I would try with something like this to make sure u get a new reference:

test$: BehaviourSubject<any> = new BehaBehaviourSubject(null);

and then:

this.facilityProtoService.facilityProto$.pipe.subscribe(tap(i => { console.log(Object.keys(i));
test$.next(Object.keys(i);
});

Upvotes: 1

P.Brian.Mackey
P.Brian.Mackey

Reputation: 44295

It looks like the syntax is a little off. Check your console output for errors. Try

<ng-container *ngIf="test$ | async as tests">
    <ng-container *ngFor="let key of tests; trackBy: trackByFn">
        {{ key }}<br>
    </ng-container>
</ng-container>

Upvotes: 1

Related Questions