Search code examples
angularsvgangular-material

Angular Light/Dark Mode Switcher Reloads Entire Page When Clicking


I'm working on an Angular application with a light/dark mode switcher. The switcher is supposed to toggle between light and dark mode and also change the logo (which is an SVG image) accordingly. However, when I click on the switcher, it appears as though the entire page reloads. Clicking on the theme switcher causes the whole page to refresh or reload.

I have a StackBlitz demo where I've tried to implement this, but I couldn't manage to include the SVG images properly.

What I need help with:

  • Understanding why clicking the switcher might cause the page to reload.
  • Correct way to handle SVG images and switch them dynamically without causing a page reload.

Any guidance or suggestions on how to resolve this issue would be greatly appreciated!

Stackblitz Demo

main.ts

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [],
  template: `
  @if (this.counter%2) {
      <img src="light.svg" alt="light-logo">

    } @else {
      <img src="dark.svg" alt="dark-logo">
    }
    <button type="button" (click)="changeTheme()">Change Theme</button>
  `,
})
export class App {
  name = 'Angular';
  counter = 0;

  public changeTheme() {
    this.counter++;
  }
}

Solution

  • The page does not reload, you can check this by putting a console.log on ngOnInit, you will notice it's only called once on load. For the ugly transition you can use Angular animations to make the transition a bit more pleasing.

    trigger('fadeInOut', [
      transition(':enter', [
        // :enter is alias to 'void => *'
        style({ opacity: 0 }),
        animate(500, style({ opacity: 1 })),
      ]),
      // transition(':leave', [   // :leave is alias to '* => void'
      //   animate(500, style({opacity:0}))
      // ])
    ]),
    

    Full Code:

    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import 'zone.js';
    import { provideAnimations } from '@angular/platform-browser/animations';
    import { trigger, style, animate, transition } from '@angular/animations';
    @Component({
      selector: 'app-root',
      standalone: true,
      animations: [
        trigger('fadeInOut', [
          transition(':enter', [
            // :enter is alias to 'void => *'
            style({ opacity: 0 }),
            animate(500, style({ opacity: 1 })),
          ]),
          // transition(':leave', [   // :leave is alias to '* => void'
          //   animate(500, style({opacity:0}))
          // ])
        ]),
      ],
      imports: [],
      template: `
      @if (this.counter%2) {
          <img src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg" alt="light-logo"  [@fadeInOut]>
    
        } @else {
          <img src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/acid.svg" alt="dark-logo"  [@fadeInOut]>
        }
        <button type="button" (click)="changeTheme()">Change Theme</button>
      `,
    })
    export class App {
      name = 'Angular';
      counter = 0;
    
      public changeTheme() {
        this.counter++;
      }
    
      ngOnInit() {
        console.log('asdf');
      }
    }
    
    bootstrapApplication(App, {
      providers: [provideAnimations()],
    }).catch((err) => console.error(err));
    

    Stackblitz Demo