1

In an effort to pass a variable into app.component.ts from another component I created a service (see Global.service.ts below.)

This works well when my nav.component.ts calls the service. However, it doesn't work in app.component.ts. I don't understand why, as the code is the same (see app.component.ts below.)

Nav.component.ts is in a module (global.module.ts). global.module.ts has been added to the imports [] in app.module.ts.

Global.service.ts

@Injectable()
export class GlobalService {
  private handleError: HandleError;
  isOpen = false;

  private _change: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  constructor(
   private http: HttpClient,
   httpErrorHandler: HttpErrorHandler
  ) {

  this.handleError = httpErrorHandler.createHandleError('GlobalService');
 }

get change(): Observable<boolean> {
  return this._change.asObservable();
}

toggle() {
 this.isOpen = !this.isOpen;
 this._change.next(this.isOpen);
}

}

app.component.ts

import { Component, OnInit } from '@angular/core';
import { GlobalService } from './globals/global.service';

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  isOpen = true;

  constructor(
    private _globalService: GlobalService,
  ) {
 }

ngOnInit(): void {
  console.log("foo bar");

  this._globalService.change.subscribe(isOpen => {
    this.isOpen = isOpen;
    console.log(this.isOpen);
  });

 }
}

nav.component.ts

ngOnInit(): void {

//
this.getNav();

  this._globalService.change.subscribe(isOpen => {
    this.isOpen = isOpen;
    this.NavToggle(this.isOpen);
  });

}

//Toggle
hideShowSidebar() {
    this._globalService.toggle();
}
Mark
  • 2,543
  • 6
  • 33
  • 44
  • `@Output()` would not be used with a service. It's used with components. Check out [Parent and children communicate via a service](https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service) – Alexander Staroselsky Feb 06 '19 at 16:35
  • Hmmm, let me look. I got that code from here: https://medium.com/@mirokoczka/3-ways-to-communicate-between-angular-components-a1e3f3304ecb – Mark Feb 06 '19 at 16:40
  • https://stackoverflow.com/questions/50647693/eventemitter-in-angular-services-good-or-bad – Alexander Staroselsky Feb 06 '19 at 16:46

1 Answers1

2

The @Output (and @Input) decorators are typically used for attributes/properties of components/elements to detect events (and assign values), I would say that it would not be the best way for a Service to emit an update to a Component. For that you could use a simple BehaviorSubject and just a little change to your service.

@Injectable()
export class GlobalService {
 private handleError: HandleError;
 isOpen = false;
 private _change: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  constructor(
   private http: HttpClient,
   httpErrorHandler: HttpErrorHandler
  ) {

  this.handleError = httpErrorHandler.createHandleError('GlobalService');
 }

 get change(): Observable<boolean> {
  return this._change.asObseravble();
 }

 toggle() {
  this.isOpen = !this.isOpen;
  this._change.next(this.isOpen);
 }
}

Since the _change BehaviorSubject provides as a source of truth for components/classes outside of itself, we do not want to expose it (as it can be easily changed). That is why we provide it through the getter as an Observable. This should work however if you have the service imported into the providers of multiple modules, you may have multiple instances of the service (and they wouldn't all have the same data). If that is the case it would be best to only have your service declared in only your AppModule.

MichaelSolati
  • 2,847
  • 1
  • 17
  • 29
  • So this does work in my nav component, but not my app.component.ts. Perhaps it should not be called from ngOnInit()? I need it to listen to when the variable changes ? – Mark Feb 06 '19 at 17:06
  • Definitely listen on the OnInit, but as mentioned, your app structure may make a difference as well. What module(s) are your app component, navbar component and service included in? – MichaelSolati Feb 06 '19 at 17:08
  • I updated the code above. nav.component.ts is part of a global.module.ts. global.module.ts has been added to the imports [] in app.module.ts. – Mark Feb 06 '19 at 17:19
  • It does appear in app.component.ts that it gets called ngOnit(), but never again when it gets updated from the nav.component.ts – Mark Feb 06 '19 at 17:24
  • Could you remove any reference of the global service from the global module, and only import it into the app module. It is possible that two instances of the service exist and your issue stems from that. Otherwise I may need to see a StackBlitz – MichaelSolati Feb 06 '19 at 17:30
  • You got it mate. I have a reference to the service in my providers [] in global.component.ts that was killing things. once removed it works. Thanks! – Mark Feb 06 '19 at 17:49