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

Dark Theme Issue with Angular Material's CheckBox in Mat-Menu

If you try to place a <mat-checkbox> inside a <mat-menu>, the dark themes won't apply to the text part of your <mat-checkbox>. Look at the image at the end for reference. A similar issue arises with <mat-label>s. However, the ...

Is it not possible to utilize inline "if" statements in conjunction with useEffect within a functional React component?

I'm currently working on integrating Okta's React SDK into a TypeScript-based application using functional components instead of class-based ones. My main challenge lies in rendering a part of the app's menu based on the user's authenti ...

Unable to locate $element post minification

I've encountered a peculiar bug that only seems to manifest when my web application is running in Karaf, but not on the webpack-dev-server. Whenever I open a dialog while the web app is running in Karaf, I receive this error in the browser console: a ...

Displaying nested web service array data in Angular 4

I created a project that retrieves data from a web service API. However, the API contains nested arrays that also need to be displayed. How can I access the data from these nested JSON arrays? What is the correct way to extract this data within the HTML co ...

The entry for "./standalone" in the "@firebase/database-compat" package does not have any documented conditions

Upon running npm run build for my sveltekit project, I encountered the following error generated by vite: 7:55:49 PM [vite-plugin-svelte] When trying to import svelte components from a package, an error occurred due to missing `package.json` files. Contact ...

Tips for refining TypeScript discriminated unions by using discriminators that are only partially known?

Currently in the process of developing a React hook to abstract state for different features sharing common function arguments, while also having specific feature-related arguments that should be required or disallowed based on the enabled features. The ho ...

Storing and sharing information between routes in Angular 2: The ultimate guide

As I launch my angular app, I make a request to an endpoint during initialization to retrieve data for specific routes. When I navigate to the home page, I fetch the home page data from the database and return it. Similarly, when I go to the contact route, ...

The issue arises when attempting to apply CSS styles to an existing component or body tag,

I am currently working on an Angular 7 project where I have a requirement to dynamically load a component using routes. However, when I try to add styles for the body tag and existing component tags in the dynamically loaded component style-sheet, they do ...

Tips for retrieving input values when they are not available in HTML documents

In this code snippet, I am creating an input element with the file type without adding it to the DOM. My goal is to retrieve the value of this input once the user selects a file. Even though the input is not part of the HTML template, I still want to acces ...

Typescript: The property isComposing is not found on Event type

While working on a React app with Typescript, I encountered a Typescript error both during compile time and in the editor: TS2339: Property isComposing does not exist on type Event This issue arises when handling an OnChange event in an HTML Input element ...

Modifying data types within complex nested object structures

I am looking to traverse the data structure recursively and create a custom type with specific fields changed to a different type based on a condition. Using the example structure below, I aim to generate a type (Result) where all instances of A are repla ...

Examining for a TypeError with Typescript and Jasmine

In my current project, I am faced with the challenge of writing unit tests in Typescript for an existing library that was originally written in plain JS. Most of our page logic is also written in plain JS. Some functions in this library throw exceptions if ...

Tips for customizing the color of a leaflet-routing-machine marker

I'm currently utilizing the leaflt-routing-machine plugin, and I'm looking to alter the color of markers from blue to red. Any ideas or suggestions on how to achieve this?! ...

Restricting the type of user input in HTML forms

Requirements: Input must be a whole number between 2 and 99, inclusive. Current Solution: <input required type="number" min="2" max="99" oninput="this.value = Math.abs(this.value)" maxLength="2" matInp ...

What is the best way to have text wrap around an icon in my React application?

I am facing an issue while trying to display the note description over the trash icon in a React app. I have tried various methods but can't seem to achieve the desired effect. Can anyone guide me on how to get this layout? Here is what I intend to a ...

Troubleshooting Issue with Mongoose Virtual Field Population

I am currently facing an issue with my database due to using an outdated backend wrapper (Parse Server). The problem arises when dealing with two collections, Users and Stores, where each user is associated with just one address. const user = { id: &q ...

Do Angular routes need to have distinct prefixes?

I have defined two routes. /apples---> AppleComponent, /apples/:id ---> AppleDetailComponent, When I visit /apples/111, it will first go into AppleComponent and then into AppleDetailComponent. What steps should I take to make it only match /appl ...

Error Message: The specified HTML element already contains two instances of the WebViewer, leading to a conflict in PDFTron React TypeScript Next

Having some trouble using pdftron with my docx editor. I can use the editor fine, but keep encountering an error like the one shown below: https://i.stack.imgur.com/OnJxE.png https://i.stack.imgur.com/l9Oxt.png Here is a snippet of my code: wordeditor.t ...

Upon updating my Angular application from version 5.2 to the most recent one, I encountered an ERROR when running ng build

There was an error in the file ./src/styles.css (./node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/raw-css-loader.js!./node_modules/postcss-loader/src??embedded!./src/styles.css) The module build failed due to a SyntaxError (60: ...

Learn how to configure an Angular2 Template Driven form element by implementing two-way binding and integrating template driven form validation techniques

Can anyone help me figure out the correct way to set up an Angular template driven form element for both validation and two-way binding? I've tried using ngModel in different ways, but cannot seem to achieve two-way binding without encountering issues ...