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.