netik netik - 26 days ago 9
TypeScript Question

Angular2 - Waiting for service variable to be initialized

Application


  • MapViewComponent

  • SearchComponent (requires an object of the MapViewComponent)

  • MapService



So far, I placed the
SearchComponent
inside the
MapViewComponent
s template so I was able to pass it to the
SearchComponent
by using
@Inject(forwardRef(() => MapViewComponent))
. But as the search component should be displayed somewhere else within the layout / HTML DOM, I think I have to use a service to pass the
MapViewComponent
to the Search.

MapViewComponent.ts:

export class MapViewComponent {
@Output() onMapViewCreated = new EventEmitter();

private _view: any = null;

constructor(private mapService: MapService, private elRef: ElementRef) {
}

ngOnInit() {
this._view = new MapView({
container: this.elRef.nativeElement.firstChild,
map: this._mapService.map,
center: [5.44, 36.947974],
rotation: 0,
autoResize: true
})

this._view.then((view) => {
this.onMapViewCreated.next(view);
this._mapService.setView(view);
});


SearchComponent.ts:

export class SearchComponent {

constructor(private elRef:ElementRef, private mapService: MapService ) {
var view = mapService.getView();
}
}


MapService.ts:

@Injectable()
export class MapService {
public setView(mv: MapView){
this.view = mv; // what do I have to do here..?
}

public getView(){
return this.view; // .. and here?
}
}


It obviously wont work like that, because
getView()
might get called before
setView()
.

Answer

You should use a Subject (either BehaviorSubject or ReplaySubject). The Subject will act as both a producer and consumer. The consumer of it can subscribe to it, just like an observable. And the producer can use it to emit messages to consumers. For example

import { ReplaySubject } from 'rxjs/ReplaySubject'

@Injectable()
export class MapService {

  private _currentMapView = new ReplaySubject<MayView>(1);

  setCurrentView(mv: MapView){
    this._currentView.next(mv);
  }

  get currentMapView$() {
    return this._currentMapView.asObservable();
  }
}

The subscriber just needs to suscribe

import { Subscription } from 'rxjs/Subscription';

export class SearchComponent {
  sub: Subscription;
  view: MapView;

  constructor(private elRef:ElementRef, private mapService: MapService ) {
  }

  ngOnInit() {
    this.sub = this.mapService.currentMapView$.subscribe(view => {
      this.view = view;
    })
  }

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

The MapViewComponent just needs to call the setCurrentView, and it will be handled by the subscribers automatically when it's sent

See Also:

  • This post for a brief description about difference between Subject/BehaviorSubject/ReplaySubject
Comments