angulartypescriptprimeng

ERROR TypeError: Cannot read properties of null (reading 'offsetHeight') in primeng MenuModule


I am using MenuModule primeng

The model inside Menu is of type signal

And it is taken from service

Now when service is called and model is filled this error is displayed

ERROR TypeError: Cannot read properties of null (reading 'offsetHeight')

//Html Code

<h1 (click)="statusDispacherClick(213 , $event)">
    Status Click
</h1>
<p-menu #menu [model]="listStatusTypes()" [popup]="true" />

//typeScript Code

  @ViewChild('menu') menu !: Menu;
  listStatusTypes = signal<any[]>([])

  statusDispacherClick(data, event) {
    this.service.getDashboardChangeStatusTypes(data).subscribe(dataService => {
      dataService.map(x => {
        x.label = x.title;
      })
      this.listStatusTypes.set(dataService);
      this.cdRef.detectChanges();
      this.menu.toggle(event);
    })
  }

Solution

  • It looks like a bug, it happens only when we do not immediately show the menu.

    If I open the menu before the API call is done there is no issue.

    As a workaround, we can show a loading indicator, which is disabled, then open the menu and then make the API call.

    statusDispacherClick(data, event) {
        this.listStatusTypes.set([
        { label: 'Loading...', icon: 'pi pi-spin pi-spinner', disabled: true },
        ]);
        this.menu.toggle(event);
        console.log(data, event);
        this.service.getDashboardChangeStatusTypes(data).subscribe((data) => {
        const transformedData = data.map((x: any) => {
            x.label = x.title;
            return x;
        });
        this.listStatusTypes.set(transformedData);
        });
    }
    

    Full Code:

    TS:

    import {
    Component,
    OnInit,
    signal,
    ViewChild,
    inject,
    Injectable,
    ChangeDetectorRef,
    } from '@angular/core';
    import { ImportsModule } from './imports';
    import { MenuItem } from 'primeng/api';
    import { Menu } from 'primeng/menu';
    import { of, delay } from 'rxjs';
    @Injectable({
    providedIn: 'root',
    })
    export class DashboardService {
    getDashboardChangeStatusTypes(data: any) {
        return of([
        { title: 'New', icon: 'pi pi-plus' },
        { title: 'Search', icon: 'pi pi-search' },
        ]).pipe(delay(2000));
    }
    }
    
    @Component({
    selector: 'menu-basic-demo',
    templateUrl: './menu-basic-demo.html',
    standalone: true,
    imports: [ImportsModule],
    })
    export class MenuBasicDemo {
    service = inject(DashboardService);
    cdRef = inject(ChangeDetectorRef);
    @ViewChild('menu', {
        read: Menu,
    })
    menu!: Menu;
    listStatusTypes = signal<any[]>([]);
    
        statusDispacherClick(data, event) {
            this.listStatusTypes.set([
            { label: 'Loading...', icon: 'pi pi-spin pi-spinner', disabled: true },
            ]);
            this.menu.toggle(event);
            console.log(data, event);
            this.service.getDashboardChangeStatusTypes(data).subscribe((data) => {
            const transformedData = data.map((x: any) => {
                x.label = x.title;
                return x;
            });
            this.listStatusTypes.set(transformedData);
            });
        }
    }
    

    HTML:

    <h1 (click)="statusDispacherClick(213 , $event)">
    Status Click
    </h1>
    <p-menu #menu [model]="listStatusTypes()" [popup]="true" />
    

    Stackblitz Demo