2
votes

I'm running into a weird issue where the mat-select stops opening.

I will be using the application and the mat-selects will open and let me select an option. Then I'll come back later and it won't open anymore. It happens very randomly and is very unpredictable.

I've noticed that when I click the element, it still appends the aria-owns property and adds the options (see below) to that property but it no longer adds the options to the cdk-overlay container.

I don't have any browser errors in the console.

EDIT

I have been watching the performance monitor in Chrome Dev Tools and the CPU usage is always very low and the JS heap size never really goes up.

It also happens on all of our mat-selects, even on different pages.

Code For The Mat-Select

<mat-select [value]="column.source" class="bg-neutral-2 padding-2 line-height-4 border-radius-3 box-xs" placeholder="- select -" (selectionChange)="onColumnChange($event.value, columnIndex)">
    <mat-option class="font-size-1" value="ignore" *ngIf="column.source">- ignore -</mat-option>
    <mat-option class="font-size-1" *ngFor="let source of sortedSourceColumns" [value]="source.value" >{{source.name}}</mat-option>
</mat-select>

Clicking On The Element

When I click on the element, it appends the mat options to the mat-select aria-owns property but the options don't get added to the cdk overlay container.

mat-select

<mat-select _ngcontent-c5="" class="bg-neutral-2 padding-2 line-height-4 border-radius-3 box-xs mat-select ng-tns-c7-6 mat-select-empty" placeholder="- select -" role="listbox" id="mat-select-4" tabindex="0" aria-label="- select -" aria-required="false" aria-disabled="false" aria-invalid="false" aria-multiselectable="false" aria-owns="mat-option-21 mat-option-22 mat-option-23 mat-option-24 mat-option-25 mat-option-26 mat-option-27 mat-option-28 mat-option-29 mat-option-30 mat-option-31 mat-option-32 mat-option-33 mat-option-34 mat-option-35 mat-option-36 mat-option-37" aria-activedescendant="mat-option-21"><div class="mat-select-trigger" aria-hidden="true" cdk-overlay-origin=""><div class="mat-select-value"><!----><span class="mat-select-placeholder ng-tns-c7-6 ng-star-inserted">- select -</span><!----></div><div class="mat-select-arrow-wrapper"><div class="mat-select-arrow"></div></div></div><!----></mat-select>

cdk-overlay-container

<div class="cdk-overlay-container"></div>

Any thoughts what could be causing this?

Dependencies

    "@angular/animations": "~7.0.0",
    "@angular/cdk": "^7.0.4",
    "@angular/common": "~7.0.0",
    "@angular/compiler": "~7.0.0",
    "@angular/core": "~7.0.0",
    "@angular/forms": "~7.0.0",
    "@angular/http": "~7.0.0",
    "@angular/material": "~7.0.4",
    "@angular/platform-browser": "~7.0.0",
    "@angular/platform-browser-dynamic": "~7.0.0",
    "@angular/router": "~7.0.0",
1

1 Answers

1
votes

For anyone else that runs into this, in my case it ended up being an issue of running to Angular applications on the same page using single-spa and both applications used Angular Material.

Angular Material uses the cdk-overlay to append the options and since there were multiple applications, the applications were getting confused which overlay to add the options to.

I fixed it by adding a custom class to clean up the overlays in each of my micro front ends using the code below:

microfrontend-overlay-container.ts

import { OverlayContainer } from '@angular/cdk/overlay';

@Injectable()
export class MicrofrontendOverlayContainer extends OverlayContainer {
  protected _createContainer(): void {
    const containerClass = 'cdk-overlay-container';
    const previousContainers = this._document.getElementsByClassName(containerClass);

    // If there is already a container (can happen in a Microfrontend scenario with
    // multiple self-contained Angular apps on the same website), reuse that. But
    // clean it up because it could be created while transitioning from server
    // to client (Angular Universal) and may be stale. Remove any additional containers.
    for (let i = 0; i < previousContainers.length; i++) {
      while (i === 0 && previousContainers[i].firstChild) {
        previousContainers[i].removeChild(previousContainers[i].firstChild);
      }

      if (i > 0 && !!previousContainers[i].parentNode) {
        previousContainers[i].parentNode.removeChild(previousContainers[i]);
      }
    }

    if (previousContainers.length > 0) {
      this._containerElement = previousContainers[0] as HTMLElement;
      return;
    }

    const container = this._document.createElement('div');
    container.classList.add(containerClass);
    this._document.body.appendChild(container);
    this._containerElement = container;
  }
}

app.module.ts

Add this to the providers array:

{ provide: OverlayContainer, useClass: MicrofrontendOverlayContainer }