mat-icon shows text before showing properly
  • 29-May-2023
Lightrun Team
Author Lightrun Team
Share
mat-icon shows text before showing properly

mat-icon shows text before showing properly

Lightrun Team
Lightrun Team
29-May-2023

Explanation of the problem

Expected Behavior: When utilizing the <mat-icon>home</mat-icon> component in Angular Material, the expected behavior is that no content should be displayed until the icon is loaded successfully. Once the icon is fully loaded, it should be rendered without any delay or flickering.

Current Behavior: However, the current behavior exhibits an issue where, depending on the network speed, there is a possibility of seeing the text representation (e.g., “home”) instead of the actual icon. This behavior occurs due to the asynchronous loading of the icon font, resulting in an inconsistent rendering experience for the user.

Steps to Reproduce: To reproduce this issue, follow the steps below:

  1. Launch the Angular Material Icon example on Stackblitz or open it in a separate tab.
  2. Open the Developer Tools in Google Chrome and navigate to the Network tab.
  3. Choose a network throttling profile that simulates a very slow network connection. This step is crucial since the sample app is small, making the problem less noticeable with normal network speeds.
  4. Reload the page and observe the loading sequence. Initially, you will see the text representation of the icon, and after a certain delay, the actual icon will be displayed.

Troubleshooting with the Lightrun Developer Observability Platform

Getting a sense of what’s actually happening inside a live application is a frustrating experience, one that relies mostly on querying and observing whatever logs were written during development.
Lightrun is a Developer Observability Platform, allowing developers to add telemetry to live applications in real-time, on-demand, and right from the IDE.

  • Instantly add logs to, set metrics in, and take snapshots of live applications
  • Insights delivered straight to your IDE or CLI
  • Works where you do: dev, QA, staging, CI/CD, and production

Start for free today

Problem solution for mat-icon shows text before showing properly

One common solution to address the issue of material icons momentarily displaying as text before they are fully loaded is to implement a self-hosting approach for the material icons font. By following the self-hosting setup method recommended in the Material Design Icons documentation, which can be found at https://google.github.io/material-design-icons, the required CSS snippets for @font-face and .material-icons classes are provided. In the @font-face CSS snippet, adding the font-display: block property ensures that the font is not displayed until it is fully loaded, eliminating the brief visibility of text representations.

The font-display: block property, as described in the Mozilla Developer Network (MDN) documentation on @font-face, controls how a font is displayed during the loading process. By setting it to block, the font is only rendered when it is fully loaded, preventing any text fallback from being shown. This approach ensures a consistent rendering experience for material icons, regardless of the network speed or loading context.

By implementing the suggested fix and adding the font-display: block property to the @font-face CSS snippet for the material icons font, developers can eliminate the issue of icons momentarily displaying as text. This solution is highly recommended, especially when self-hosting the material icons font. It ensures that icons are only visible once they are fully loaded, providing a seamless and consistent user experience across different network speeds and application contexts.

Other popular problems with Angular components

Problem: Change Detection Performance Issues

One of the most common problems with Angular components is change detection performance issues. When Angular updates the component view based on changes in the component’s data, it runs change detection on every component, which can have a significant impact on application performance when the component tree is large.

Solution:

To mitigate this issue, you can use OnPush change detection strategy, which only runs change detection on a component when an input value changes. You can set the change detection strategy in the component’s metadata using the changeDetection property:

@Component({
  selector: 'app-my-component',
  template: `...`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
  ...
}

Another solution is to use the ngDoCheck lifecycle hook to manually control when change detection should be run:

@Component({
  selector: 'app-my-component',
  template: `...`
})
export class MyComponent implements DoCheck {
  ...
  ngDoCheck() {
    // Perform change detection only if a specific condition is met
    if (this.shouldRunChangeDetection) {
      ...
    }
  }
}

Problem: Memory Leaks

Another common issue with Angular components is memory leaks caused by improperly managed subscriptions or leaking DOM elements. Subscriptions to observables should always be unsubscribed in the ngOnDestroy lifecycle hook to prevent memory leaks:

export class MyComponent implements OnDestroy {
  private subscription: Subscription;

  ngOnInit() {
    this.subscription = this.myService.data$.subscribe(data => {
      ...
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Memory leaks can also occur when a DOM element is referenced in a component and the element is not removed from the DOM when the component is destroyed.

Solution:

To prevent this issue, make sure to remove any references to DOM elements in the ngOnDestroy lifecycle hook:

export class MyComponent implements OnDestroy {
  private elementRef: ElementRef;

  constructor(elementRef: ElementRef) {
    this.elementRef = elementRef;
  }

  ngOnDestroy() {
    this.elementRef.nativeElement.remove();
  }
}

Problem: Inconsistent Component State

Inconsistent component state can occur when multiple components share the same data or when the state of a component changes in an unexpected way. This can lead to bugs and unexpected behavior in your application.

Solution:

To mitigate this issue, you can use a centralized store, such as NgRx or Akita, to manage the state of your application. This ensures that all components receive the same data and updates in a consistent and predictable manner.

For example, using NgRx, you can create a store and an action to update the state:

// store.ts
export interface State {
  count: number;
}

const initialState: State = {
  count: 0
};

export function reducer(state = initialState, action: any): State {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }

A brief introduction to Angular components

Angular components are the fundamental building blocks of an Angular application. They define views, which are sets of user interface elements (UI elements) that belong together and have a specific function within the overall application. Components are written in TypeScript and use the Angular framework to manage data and user interactions.

Each component is made up of three parts: an HTML template, a class definition (in TypeScript), and metadata (in the form of decorators). The template defines the UI for the component, the class defines its behavior and state, and the decorators define its metadata, such as its selector, which is used to define the component’s name and how it can be included in other components’ templates. Components can also communicate with each other, with parent components able to pass data to child components via inputs, and child components able to send data back to the parent via outputs. Overall, the use of components in Angular allows for a clean separation of concerns, with each component responsible for a well-defined portion of the overall application.

Most popular use cases for Angular components

  1. Modularizing User Interface Design: Angular components allow developers to modularize their user interface design into smaller, reusable components. This means that developers can break down complex UI designs into smaller, manageable parts and reuse them in other parts of the application. This leads to a more maintainable and scalable codebase.
  2. Managing State and Event Handling: Angular components can be used to manage state and event handling in an application. A component can maintain its own internal state, which can be updated in response to events that occur within the component. This helps to encapsulate the logic for a particular part of the application, making it easier to reason about and manage.
  3. Improved Performance: Angular components are optimized for performance, as they are designed to update only the parts of the UI that have changed. This helps to reduce the amount of DOM manipulation required, leading to faster updates and better overall performance. Additionally, Angular provides advanced change detection algorithms that help to further optimize updates.

Here is a simple example of an Angular component that updates its internal state based on a button click:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>{{title}}</h1>
    <button (click)="updateTitle()">Update Title</button>
  `
})
export class AppComponent {
  title = 'Angular Components';

  updateTitle() {
    this.title = 'Updated Title';
  }
}
Share

It’s Really not that Complicated.

You can actually understand what’s going on inside your live applications.

Try Lightrun’s Playground

Lets Talk!

Looking for more information about Lightrun and debugging?
We’d love to hear from you!
Drop us a line and we’ll get back to you shortly.

By clicking Submit I agree to Lightrun’s Terms of Use.
Processing will be done in accordance to Lightrun’s Privacy Policy.