Enhancing Angular Material: requiring more user engagement for rendering to occur

Encountering an unusual issue with Angular Material: certain components require an additional event, like a click or mouse movement on the targeted div, to trigger the actual rendering process. For instance, when loading new rows in mat-table, some empty rows remain visible until scrolled or clicked, at which point they disappear. Similarly, with dialogs, clicking outside the border initially has no effect, but subsequent clicks or scrolls cause it to vanish. Here is the version of Angular CLI I am using.


Angular CLI: 8.3.14
Node: 13.0.1
OS: linux x64
Angular: 8.2.12
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.803.14
@angular-devkit/build-angular     0.803.14
@angular-devkit/build-optimizer   0.803.14
@angular-devkit/build-webpack     0.803.14
@angular-devkit/core              8.3.14
@angular-devkit/schematics        8.3.14
@angular/cdk                      8.2.3
@angular/cli                      8.3.14
@angular/flex-layout              8.0.0-beta.27
@angular/material                 8.2.3
@ngtools/webpack                  8.3.14
@schematics/angular               8.3.14
@schematics/update                0.803.14
rxjs                              6.5.3
typescript                        3.5.3
webpack                           4.41.2

I appreciate all the responses so far. Upon further inspection, I've identified that all issues are interconnected with the mat Table component. For example, moving the problematic dialog trigger from inside the table to outside resolves the problem. Here are the main components of the table:


export class MainComponent implements OnInit {
    
    dataSource : MyTableSource;
    @ViewChild(MatTable, {static:true}) table: MatTable<any>;
    dtOptions: any = { 
            displayedColumns : [ 'colA', 'colB', 'colC', 'colD'],
            search : { value : "" } ,
            order : { name : 'values' , asc : true },
            subset : [] , 
            pageSize : 10,
            pageIndex : 0,
            draw : 0 , 
            recordsTotal : 0, 
            recordsFiltered : 0};

    constructor(public dialog: MatDialog,
            private _snackBar: MatSnackBar,private trackService: TracksService) {
    };
   ngOnInit() {
        this.dataSource = new KmerTableSource(this.trackService);
   }
   refreshTable(event?:any){
        if ( event){
            if ( event.pageSize){
                this.dtOptions.pageSize=event.pageSize;
                this.dtOptions.pageIndex=event.pageIndex;
            }
            if (event.active){
                this.dtOptions.order.name = event.active;
                this.dtOptions.order.asc = event.direction == "asc";
            }
        }
        
        this.dataSource.loadData(this.dtOptions);
    }
    
}
   

The html

<table mat-table matSort (matSortChange)="refreshTable($event)" [dataSource]="dataSource" >
                        <ng-container matColumnDef="importance">
                            <th mat-header-cell *matHeaderCellDef  mat-sort-header>Col A</th>
                            <td mat-cell *matCellDef="let row">{{row.A}}</td>
                        </ng-container>
                        <ng-container matColumnDef="kmer">
                            <th mat-header-cell *matHeaderCellDef  mat-sort-header>Col B</th>
                            <td mat-cell *matCellDef="let row">{{row.B}}</td>
                        </ng-container>
                        <ng-container matColumnDef="position">
                            <th mat-header-cell *matHeaderCellDef  mat-sort-header>Col C</th>
                            <td mat-cell *matCellDef="let row">{{row.C}}</td>
                        </ng-container>
                        
                        <tr mat-header-row *matHeaderRowDef="dtOptions.displayedColumns;sticky : true;"></tr>
                        <tr mat-row cdk-row *matRowDef="let row; columns: dtOptions.displayedColumns"></tr>
                    </table>


The data source


@Injectable({
  providedIn: 'root'
})


export class MyTableSource implements DataSource<DataPoint> {
  private dataSubject = new BehaviorSubject<DataPoint[]>([]);
    
  constructor(private trackService :TracksService ) { }

  connect(collectionViewer: CollectionViewer): Observable<DataPoint[]> {
      return this.dataSubject.asObservable();
  }

  disconnect(collectionViewer: CollectionViewer): void {
      this.dataSubject.complete();
  }
  
  loadData(request : any) {
      this.trackService.getDataTable(request).pipe(
              catchError(()=>of([])),
      ).subscribe(response => {
          this.dataSubject.next(response);
       });
  }
  
}

  

The track service (utilizing electron)


@Injectable( {
    providedIn: 'root'
} )


export class TracksService {
    protected request: number = 0;
    protected ipc : IpcRenderer;
    constructor( protected http: HttpClient ) {
        if ( ( <any>window ).require ) {
            try {
                this.ipc = ( <any>window ).require( "electron" ).ipcRenderer;
            } catch ( error ) {
                throw error;
            }
        } else {
            console.warn( "Could not load electron ipc" );
        }
    }
    
    getDataTable( dataTablesParameters : any) : Observable<any[]>{
        var id = this.request;
        this.request += 1;
        this.ipc.send( "getData" , id, dataTablesParameters);
        return new Observable<any[]>(observer => {
            this.ipc.once( "getData-" + id, ( event, arg ) => {
                dataTablesParameters.recordsTotal= arg.recordsTotal;
                dataTablesParameters.recordsFiltered=arg.recordsFiltered;
                observer.next(arg.data);
            });
        });
    }
    
}

Answer №1

Resolved by utilizing NgZone and ChangeDetectorRef: it appears that the function call was made within the MatTable component without triggering changes in the subscription to be rendered in the main component.

In the main component:

refreshTable(event?:any){
        ...
        this.dataSource.loadData(this.dtOptions).then(()=>this.cd.markForCheck());
    }

The dataSource's loadData method now needs to return a Promise in order to execute markForCheck after the loading is complete

loadData(request : any) : Promise<void> {
return new Promise(resolve, reject )=>{...})
}

Additionally, for handling the dialog, utilizing NgZone.run is recommended

this.zone.run(()=>{this.dialog.open(...)}));

Credit to @gsa.interactive for providing the ChangeDetectorRef hint

Answer №2

Dealing with a similar situation, I found that utilizing material components to derive their values from an Input() attribute was effective. To ensure proper detection of changes, the ChangeDetectorRef should be implemented either in ngOnChanges or ngAfterContentInit methods.

export class MyComponent {
  @Input() data: string[];

  constructor(private cd: ChangeDetectorRef) { }

  ngAfterContentInit() {
    this.cd.detectChanges();
  }
}

If necessary, consider switching to the push change detection strategy:

@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
...
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Demonstrate JSON data using ngFor loop in Angular

Need some assistance here. Trying to display data from a .json file using a ngFor loop. However, I keep running into the following error in my code: Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgF ...

Injecting configurable middleware dependencies in Nest.js allows for dynamic customization of middleware

While many tutorials demonstrate how to inject providers into dynamic modules, most of them only focus on services and not middleware. The challenge arises when attempting to create reusable middleware that also requires injected providers. For instance, ...

What is the proper way to write a function that verifies the presence of a key in an object and then retrieves the associated value?

After holding out for a while hoping to stumble upon the solution, I've decided to give it a shot here on SO since I haven't found it yet. import { PDFViewer, MSViewer } from './viewerclasses' //attempting to incorporate a union of key ...

How to implement saving TypeScript Map() in Firebase Cloud Functions?

I am currently developing a Firebase Cloud Functions application using TypeScript that is designed to save an instance of Map() to Cloud Firestore. The map consists of user IDs as keys and objects with 2 simple attributes as values. Due to the dynamic natu ...

To effectively run the Angular Compiler, it is necessary to have TypeScript version greater than or equal to 2.7.2 but less than 2.8.0. However, the system detected

I am encountering an error in my Angular application that reads: The Angular Compiler is asking for TypeScript version >=2.7.2 and <2.8.0, but it found 2.8.3 instead. When I attempt to downgrade TypeScript to the correct version by running: npm instal ...

Striking through the value of a Material-UI TextField variant label

For my project, I attempted to implement the TextField component from Material-UI in the outlined variant. However, I encountered an issue where the label overlaps with the value. How can I resolve this issue? Check out this screenshot showing the mixed-u ...

Each time the Angular Service is called, it undergoes a reset process

For my Angular web project, I have implemented an AuthenticationGuard and an AuthenticationService to manage security. These components are from a separate branch of the project that is functioning perfectly. This is how the process should occur: Go to ...

"Take control of FileUpload in PrimeNG by manually invoking it

Is there a way to customize the file upload process using a separate button instead of the component's default Upload button? If so, how can I achieve this in my code? Here is an example of what I've attempted: <button pButton type="button" ...

Using import statement is mandatory when loading ES Module in TS Node: server/src/index.ts

Attempting to kickstart a TypeScript Node project, I've gone ahead and added some essential dependencies (TypeScript, ESLint, Mongoose, and GraphQL). However, upon executing the command: ts-node-dev --respawn --transpile-only src/index.ts An error me ...

What is the best way to utilize the next-env.d.ts file within Next.js?

In my Next.js TypeScript project, I came across a file named next-env.d.ts. This got me thinking about how I can declare enums that would be accessible across all my Next.js files. Can you guide me on how to achieve this and use the enums throughout my p ...

What is preventing NgClass from applying the CSS styles?

I'm currently facing an issue in Angular2 where I am trying to apply different styles using ngClass within an 'NgFor' loop, but for some reason, it's not working as expected. Apologies for any language errors. <div class='line ...

"What is the most effective way to utilize and integrate the `setValue` function from react-hook-form within a custom react hook

Struggling to pass setValue to a react hook? In my custom react hook, I need to set values in a form using react-hook-form's setValue. Yet, after migrating from v6 to v7, I'm having trouble figuring out the proper typing for this. This is how t ...

Emphasize the text based on the content in Angular

database of customers check customer records customer service module access service details component for user details display view user details component 1 view user details component 2 template file for user details component see HTML template Seek ...

Issue with ESLint error in TypeScript PrimeReact async Button click handler

I am currently facing an issue with exporting data from a DataTable in PrimeReact. The onClick function for the Button does not allow async callbacks as flagged by eslint. Can someone guide me on how to properly call this function? const exportCSV = us ...

Utilizing nested objects in ngrx/store effects

Currently, I am in the process of learning Angular 2 and experimenting with ngrx/store. However, I am encountering some challenges when it comes to dealing with certain special cases. For instance, one issue I am facing is attempting to remove a parent ob ...

Ways to verify the functionality of a function utilizing a Subscription that yields no return value

I'm working with a TypeScript ModelService that has an edit function: edit(model: Model): Observable<Model> { const body = JSON.stringify(model); return this.http.put(`/models/edit/${model.id}`, body)); } Additionally, there is a TypeScrip ...

When transmitting data from NodeJS, BackBlaze images may become corrupted

I have been facing a challenge in my React Native app where I am attempting to capture an image and then post it to my NodeJS server. From there, I aim to upload the image to BackBlaze after converting it into a Buffer. However, every time I successfully u ...

It seems like there is an issue with your network connection. Please try again

Recently, I made the switch to EndeavourOS, which is based on Archlinux. I completed all my installations without any issues and attempted to create a new NestJs project after installing NVM, Node's latest version, and the NestJs/cli. However, when I ...

What is the best way for me to bring in this function?

Currently, I am in the process of developing a point-of-sale (POS) system that needs to communicate with the kitchen. My challenge lies in importing the reducer into my express server. Despite multiple attempts, I have been unable to import it either as a ...

Angular 5+ does not have any compatible call signatures for Type Search

Utilizing an addItem function that I found on this site, I encountered the following error message: Error TS2349 (TS) Cannot invoke an expression whose type lacks a call signature. Type 'Search' has no compatible call signatures. Definition o ...