Jayden
Jayden

Reputation: 283

Handling a boolean field in component and service class - Angular 2

Hello I am basically new to Angular, Here I'm trying to access a boolean variable from service. A boolean variable with value true, I've declared in service. Based on some logic I'm going to change that service variable to false. That particular variable I'm using in several components. So I'm facing problem like, Initial value which I've assigned true is coming to all components where I've used, but after changing the value that is not reflecting in all components. Service class like this:

@Injectable()
export class MyService { 
running: boolean = true;
}

Component 1:

export class FirstComponent {
  constructor(private myService: MyService) { }
  check(){
  this.myservice.running = false;
  }
}

Component 2:

export class SecondComponent implements OnChanges {
      running;
      constructor(private myService: MyService) { }
      ngOnChanges(){
      this.running = this.myService.running;
      console.log('running', this.running);
      }
    }

This is the how I'm going to change boolean value and accessing from service in different components. I'm not sure whether this is correct approach or not, please correct me.

Upvotes: 1

Views: 6819

Answers (3)

DeborahK
DeborahK

Reputation: 60548

How about a simple answer:

1) If you are using Angular v6 or newer, then simply change your service to the following:

@Injectable(providedIn: 'root')
export class MyService { 
   running: boolean = true;
}

2) Search your system and ensure that the MyService service is NOT listed in the providers array of any module or component.

3) Change your component to use a getter. As others have said, the ngOnChanges only works for @Input properties.

  export class SecondComponent {
      running;
      constructor(private myService: MyService) { }

      get running(): boolean {
        return this.myService.running;
      }
    }

That should do it!

When the value changes in the service, Angular's built-in change detection will pick up the change and reget the value, calling the getter and providing the updated value to the template.

You do not need a Subject or BehaviorSubject for something as straightforward as this. (Those are waaaay overused IMHO.)

I have a very simple (and similar) example here: https://stackblitz.com/edit/angular-simpleservice-deborahk

It uses a string, but would work exactly the same for a Boolean.

Upvotes: 5

web.dev
web.dev

Reputation: 359

At first, you must be sure that your service is singleton or at least have only one instance within scope of every component that you want to connect. The easiest way to achieve this is registering your service inside AppModule inside providers and nowhere else.

Second thing is that even if your service changes it's value, ngOnChanges will not be called without reason. It needs to be called by change detector, but service does not cause running change detection in way you are trying to use it.

Instead of that you should share this value with Observable.

export class TestService {
    private readonly _messageSubject: Subject<boolean>;

    get observable(): Observable<boolean> {
        return this._messageSubject.asObservable();
    }

    constructor() {
        this._messageSubject = new Subject<boolean>();
    }

    sendMessage(value: boolean): void {
        this._messageSubject.next(value);
    }
}

And now, every component which injects TestService has access to two methods:

observable which is getter. It returns observable from subject from your service. sendMessage(value: boolean) it sends your boolean message to every subscriber of _messageSubject.

If you want to subscribe that subject (and access every change of service's value) you need to use your service that way:

TestService.observable.subscribe(value => { /* You can access your boolean value here with name "value" */});

Notice that Subject shares something like changes of value, so callback inside subscribe method will only execute after every next change of that value (it means it will be called after every next call of sendMessage(value: boolean) method). If you want to access previous value (it means value which was latest before calling subscribe) use BehaviorSubject instead).

Upvotes: 1

Harun Yilmaz
Harun Yilmaz

Reputation: 8558

You could use BehaviorSubject in your service. Then create an Observable through asObservable method of subject and then subscribe to that observable in whichever component you want.

Note that ngOnChanges is changed to ngOnInit.

In Service:

private runningSubject: BehaviorSubject<boolean> = new BehaviorSubject(true);
running = this.runningSubject.asObservable();

setRunning = (value: boolean) => {
   this.runningSubject.next(value);
}

In First Component:

export class FirstComponent {
  constructor(private myService: MyService) { }
  check(){
      this.myservice.setRunning(false);
  }
}

Second Component:

export class SecondComponent implements OnInit {
      running;
      constructor(private myService: MyService) { }

      ngOnInit(){
         this.myService.running.subscribe((isRunning) => {
            this.running = isRunning;
             console.log('running', this.running);
         });

      }
}

Upvotes: 4

Related Questions