Detect Responsive Screen Sizes in Angular

Detect Responsive Screen Sizes in Angular

In this article, I would like to share about how to detect responsive breakpoints in Angular, with a twist - we don't maintaining responsive breakpoint sizes in your Typescript code (because responsive breakpoints are already defined in CSS).

In this article, I would like to share about how to detect responsive breakpoints in Angular, with a twist - we don't maintaining responsive breakpoint sizes in your Typescript code (because responsive breakpoints are already defined in CSS).

Most of the time, we use CSS media queries to handle responsive, screen size changes to layout our content differently. However, there are times where CSS media queries alone isn't sufficient for that. We need to handle the responsiveness in our code.

We will use Angular with Bootstrap in this example, but it works for any CSS frameworks and classes. Let's start.

Table of Contents

  • What's the Plan
  • The Implementation: Component
  • The Implementation: Service & Component
  • Using the Service and Component
  • Summary 

What's the Plan

We will be using CSS Classes to determine the current responsive breakpoints. There are 5 breakpoints in Bootstrap CSS. The CSS classes to determine the visibility of each breakpoints is:

  • Visible only on xs: .d-block .d-sm-none
  • Visible only on sm: .d-none .d-sm-block .d-md-none
  • Visible only on md: .d-none .d-md-block .d-lg-none
  • Visible only on lg: .d-none .d-lg-block .d-xl-none
  • Visible only on xl: .d-none .d-xl-block

The CSS display property will be toggled between none or block. We will apply these classes to HTML elements.

Everytime when screen size changes, we will loop and find the HTML element with style display: block, this is how we will detect the current breakpoint.

Here is the code if you are too excited to see the solution: https://stackblitz.com/edit/angular-size.

The Implementation: Component

Let's create an Angular component size-detector.

The component HTML template:


{{s.name}}

The component Typescript code:

// size-detector.component.ts
...
export class SizeDetectorComponent implements AfterViewInit {
  prefix = 'is-';
  sizes = [
    {
      id: SCREEN_SIZE.XS, name: 'xs', css: `d-block d-sm-none`
    },
    {
      id: SCREEN_SIZE.SM, name: 'sm', css: `d-none d-sm-block d-md-none`
    },
    {
      id: SCREEN_SIZE.MD, name: 'md', css: `d-none d-md-block d-lg-none`
    },
    {
      id: SCREEN_SIZE.LG, name: 'lg', css: `d-none d-lg-block d-xl-none`
    },
    {
      id: SCREEN_SIZE.XL, name: 'xl', css: `d-none d-xl-block`
    },
  ];

  @HostListener("window:resize", [])
  private onResize() {
    this.detectScreenSize();
  }

  ngAfterViewInit() {
    this.detectScreenSize();
  }

  private detectScreenSize() {
    // we will write this logic later
  }
}

After looking at the component code, you might be wondering where is those SCREEN_SIZE.* value come from. It is an enum. Let's create the screen size enum (You may create a new file or just place the enum in same component file)

// screen-size.enum.ts

/_ An enum that define all screen sizes the application support _/
export enum SCREEN_SIZE {
  XS,
  SM,
  MD,
  LG,
  XL
}

Also, remember to add Bootstrap to your project! You may add it via npm or yarn, but in this example, we will use the easier way. Add the cdn link in index.html.


<link rel="stylesheet" 
    href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

The code is pretty expressive itself.

  1. First, we define a list of sizes that we support and the CSS classes that used to determine each breakpoints.
  2. In the HTML, we loop through the size list, create div element, assign css and display it. Also note that we give each div an additional unique css class is-.
  3. We have a function detectScreenSize. This is where we will write our logic to detect the screen size changes. We will complete that later.
  4. We need to run the logic to everytime when screen size changes. We use the HostListener decorator to listen to the window resize event.
  5. We also need to run the logic when we first initialize the application. We need to run it during the AfterViewInit component lifecycle hook.

The Implementation: Service & Component

Now we have the component code "almost" ready, let's start implementing our resize service.

// resize.service.ts

@Injectable()
export class ResizeService {

  get onResize$(): Observable {
    return this.resizeSubject.asObservable().pipe(distinctUntilChanged());
  }

  private resizeSubject: Subject;

  constructor() {
    this.resizeSubject = new Subject();
  }

  onResize(size: SCREEN_SIZE) {
    this.resizeSubject.next(size);
  }

}

The resize service code is simple:

  1. We create a rxjs subject resizeSubject.
  2. We have a public method onResize that receive size as the parameter. It will then push the value to the resize stream. (We will call this method later in our size-detector component)
  3. Notice that we use distinctUntilChanged operator in the resize observable. We use that to reduce unnecessary notification. For example, when your screen size change from 200px to 300px, it is still consider as xs size in bootstrap. We don't need to notify in that case. (You can remove the operator if you need)
  4. We export the the resize stream as observable via onResize$. Any components, services, directives, etc can then subscribe to this stream to get notify whenever size is changed.

Next, let's go back to our size-detector component and update the detectScreenSize logic.

// size-detector.component.ts
...

private detectScreenSize() {
    constructor(private elementRef: ElementRef, private resizeSvc: ResizeService) { }

    const currentSize = this.sizes.find(x => {
      // get the HTML element
      const el = this.elementRef.nativeElement.querySelector(`.${this.prefix}${x.id}`);

      // check its display property value
      const isVisible = window.getComputedStyle(el).display != 'none';

      return isVisible;
    });

    this.resizeSvc.onResize(currentSize.id);
}

...

Let's breakdown and go through the logic together:

  1. First, we will need to inject the ElementRef and our newly created ResizeService to our component.
  2. Base on our CSS classes, at any point of time, there will be ONLY ONE HTML element visible. We loop through our sizes array and find it.
  3. For each size of our sizes array, we will use HTML5 element's query selector to find the element by the unique css class we defined earlier on is-.
  4. Once we find the current visible element, we then notify our resize service by calling the onResize method.

Using the Service and Component

You may place the size-detector component under our root component app-component. For example:





In this example, I have another hello-component in the app-component, but that doesn't matter.

Since I place the component in app-component, means I can use the ResizeService everywhere (directives, components, services, etc).

For instance, let's say I want to detect the screen size changes in hello-component, I can do so by inject the ResizeService in constructor, then subscribe to the onSizeChange$ observable and do what I need.

// hello.component.ts

@Component({
  selector: 'hello',
  template: `# Hello {{size}}!
`,
})
export class HelloComponent  {

  size: SCREEN_SIZE;

  constructor(private resizeSvc: ResizeService) { 
    // subscribe to the size change stream
    this.resizeSvc.onResize$.subscribe(x => {
      this.size = x;
    });
  }

}

In the above code, we detect the screen size changes and simply display the current screen size value.

See it in action!

Detect Responsive Screen Sizes in Angular

One of the real life use case scenario might be you have accordion on screen. In mobile, you would like to collapse all accordion panels, show only the active one at a time. However, in desktop, you might want to expand all panel.

Summary

This is how we can detect the screen size changes without maintaining the actual breakpoint sizes in our JavaScript code. Here is the code: https://stackblitz.com/edit/angular-size.

If you think of it, it is not very often that the user changes the screen size when browsing the app. You may handle the screen sizes changes application wide (like our example above) or just handle it everytime you need it (per use case / component basis).

Besides that, if you don't mind to duplicate and maintain the breakpoint sizes in JavaScript code, you may remove the component, move the detectScreenSize into your service and change a bit on the logic. It is not difficult to implement that. (Try it probably?)

angular css typescript

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Install Angular - Angular Environment Setup Process

Install Angular in easy step by step process. Firstly Install Node.js & npm, then Install Angular CLI, Create workspace and Deploy your App.

Angular Sass: How To Use Sass In Angular 9 Tutorial

Sass in Angular is an extension of CSS that allows you to use things like variables, nested rules, inline imports. Angular supports Sass, CSS, and Less.

Hire CSS Developer

Want to develop a website or re-design using CSS Development? We build a website and we implemented CSS successfully if you are planning to **[Hire CSS Developer](https://hourlydeveloper.io/hire-dedicated-css-developer/ "Hire CSS Developer")**...

Basics of Angular: Part-1

What is Angular? What it does? How we implement it in a project? So, here are some basics of angular to let you learn more about angular. Angular is a Typesc

Responsive Charts in Angular with D3.js and CSS

In this article, I’ll explain several problems that I used to find every time I had to do something with a visual component in Angular and D3. A better pattern for adjusting charts Responsive Charts in Angular With D3.js and CSS