Home > Mobile >  Dark mode with checkbox and local storage problem
Dark mode with checkbox and local storage problem

Time:10-24

i have a problem with loacl storage, when i activate the dark mode, it works perfectly and the local storage 'dark' is true but when i refresh the page, the local storega is correctly set to true but the toggle and the theme will be back to unchecked and theme white. for the theme dark i have added boostrap-dark.

app.sample.component.html:

  
<div >
<input  type="checkbox" id="flexSwitchCheckDefault" (change)="toggleDarkTheme()">
<label  for="flexSwitchCheckDefault">Dark Mode</label>
</div>

sample.component.ts:

    import { Component, OnInit } from '@angular/core';
     import { Observable } from 'rxjs';
     import { ThemeService } from 'src/app/service/theme.service';

     @Component({
       selector: 'app-sample',
       templateUrl: './sample.component.html',
      styleUrls: ['./sample.component.css']
     })
     export class SampleComponent implements OnInit {
       checked: boolean = false;

       constructor(
         private themeService: ThemeService
       ) {}

       ngOnInit() {
       }

       toggleDarkTheme() {
        this.checked = !this.checked;
         his.themeService.setDarkTheme(this.checked);
         console.log("Dark Theme > ", this.checked);

     }

     }        

theme.service.ts:

    import { Injectable } from '@angular/core';
     import { Subject } from 'rxjs';

     @Injectable({
       providedIn: 'root'
     })
     export class ThemeService {
       constructor() { }

       private _themeDark: Subject<boolean> = new Subject<boolean>();

       isThemeDark = this._themeDark.asObservable();

       setDarkTheme(isThemeDark: boolean) {

         this._themeDark.next(isThemeDark);

         if (isThemeDark == true) {
           console.log('Dark Used');
           document.body.className = 'bootstrap-dark';
           localStorage.setItem('dark', 'true');
         }
         else {
          console.log('Light Used');
           document.body.className = 'bootstrap';
           localStorage.setItem('dark', 'false');
         }

       }



     }        

CodePudding user response:

You should read the theme from local storage somewhere. The constructor of your service looks like a good place to do it. I would also suggest to turn this into a BehaviorSubject instead, so that new subscribers (observers that subscribe after the .next method was called on the subject) also get the latest emitted value:

@Injectable({
  providedIn: 'root',
})
export class ThemeService {
  private _themeDark: BehaviorSubject<boolean>;
  public isThemeDark: Observable<boolean>;
  constructor() {
    this._themeDark = new BehaviorSubject(localStorage.getItem("dark") == 'true');
    this.isThemeDark = this._themeDark.asObservable();
    this.setDarkTheme(this._themeDark.value);
  }

  public toggleDarkTheme(): void {
    this.setDarkTheme(!this._themeDark.value);
  }

  // rest of your code here
}

In order for your checkbox to reflect the state of the theme observable, you should also bind the checked attribute to whatever the observable emits:

<input  type="checkbox" id="flexSwitchCheckDefault" (change)="toggleDarkTheme()" [checked]="themeService.isThemeDark | async">

And now that we access the themeService in the template, we must make it public. The constructor of your SampleComponent should then look like this:

  constructor(
    public themeService: ThemeService
  ) {}

You should not use the checked flag from the component anymore. Leave this logic contained in the service. In your component code, call the toggleDarkTheme method from the service instead:

toggleDarkTheme(): void {
  this.themeService.toggleDarkTheme();
}

You can also make setDarkTheme method inside the service private.

  • Related