Angular NG0100: Expression has changed after it was checked – ExpressionChangedAfterItHasBeenChecked


The “ExpressionChangedAfterItHasBeenChecked” error in Angular typically occurs when there is a change in the component’s data after the initial change detection cycle has completed. This error is Angular’s way of ensuring that the application’s state remains consistent.

To resolve this error, you can follow these general steps:

  1. Identify the Issue: First, you need to identify which part of your Angular component is causing the error. Look for any code that changes data in your component after the initial rendering has occurred.
  2. Use ngAfterViewInit: If you’re changing data in your component after the initial render, consider moving that code to the ngAfterViewInit lifecycle hook. This hook is called after the initial view has been initialized, so it’s a suitable place for making changes to the component’s data.
import { Component, AfterViewInit } from "@angular/core";
@Component({
selector: "app-your-component",
templateUrl: "./your-component.component.html",
})
export class YourComponent implements AfterViewInit {
ngAfterViewInit() {
// Your code to modify data goes here
}
}
  1. Use ChangeDetectorRef: If you can’t avoid changing data after the initial render, you can manually trigger a change detection cycle using ChangeDetectorRef. Import it into your component and use it like this:
import { Component, ChangeDetectorRef } from "@angular/core";
@Component({
selector: "app-your-component",
templateUrl: "./your-component.component.html",
})
export class YourComponent {
constructor(private cdr: ChangeDetectorRef) {}
someMethodThatChangesData() {
// Your code to modify data goes here
this.cdr.detectChanges();
}
}
  1. Optimize and Refactor: In some cases, you might need to refactor your code to eliminate the need for changing data after the initial render. Consider using Angular’s built-in features like Observables, ngIf, ngFor, and ngSwitch to manage your component’s state more effectively.

Remember that the “ExpressionChangedAfterItHasBeenChecked” error can be an indication of a design issue in your application. It’s a good practice to try to structure your code in a way that minimizes these errors by following Angular’s change detection rules.

When I faced this issue I had implemented ngOnChanges on my Component which was causing this error to occur. I checked this function and added this.cdr.detectChanges() after touching the form elements in the function.

Angular custom validator for all of the fields in a group to be populated


Below is the validator function to be created. If one of the fields is populated then all of the fields should be populated as well –>

export function dependentFields(…fields: string[]) {
return (fg: FormGroup): ValidationErrors | null => {
let oneNotNull:boolean=false;
return (fields.every(fieldName => {
const field = fg.get(fieldName).value;
if (typeof field === 'number') {
if(field && field >= 0){
oneNotNull=true;
return true;
}
return false;
}
if (typeof field === 'string'){
if(field && field.length > 0){
oneNotNull=true;
return true;
}
return false;
}
})||!oneNotNull)
? null
: ({ dependentFields: 'All the dependent fields must be populated' } as ValidationErrors);
};
}

Call the validator in the component as below–>

formGroupControl = this.fb.group({
field1 : this.field1,
field2 : this.field2,
field3 : this.field3,
field4 : this.field4},
{validators:dependentFields('field1','field2') ,dependentFields('field3','field4')});

In the above call if field1 is populated then field2 is mandatory and vice versa. Similarly if field3 is populated then field4 becomes mandatory.

Angular custom validator for atleast one of the fields to be populated


Below is the validator function to be created –>

export function atLeastOne(…fields: string[]) {
return (fg: FormGroup): ValidationErrors | null => {
return fields.some(fieldName => {
const field = fg.get(fieldName).value;
if (typeof field === 'number') return field && field >= 0 ? true : false;
if (typeof field === 'string') return field && field.length > 0 ? true : false;
})
? null
: ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors);
};
}

Call the function –>

formGroupControl = this.fb.group({
field1 : this.field1,
field2 : this.field2,
field3 : this.field3,
field4 : this.field4},
{validators:atLeastOne('field1','field2') ,atLeastOne('field3','field4')});

In the above example either field1 or field2 should be populated. Otherwise it will throw a validation error.. Similarly either field3 or field4 should be populated.

Angular Material Table – Sample Code to implement search data in table


Sample code that includes a search bar and a button to perform searches:

Component Code (your-component.component.ts):

import { Component, OnInit, ViewChild } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html', styleUrls: ['./your-component.component.css'] }) export class YourComponent implements OnInit { displayedColumns: string[] = ['column1', 'column2', 'column3']; // Replace with your column names data: YourDataType[] = []; // Replace YourDataType with your data type pageSizeOptions: number[] = [5, 10, 25]; pageSize: number = 5; pageIndex: number = 0; totalItems: number = 0; searchInput: string = ''; // Input for search query @ViewChild(MatPaginator) paginator: MatPaginator; constructor() { } ngOnInit(): void { this.totalItems = yourDataArray.length; // Replace with the total number of items in your data array this.refreshData(); } onPageChange(event: PageEvent): void { this.pageSize = event.pageSize; this.pageIndex = event.pageIndex; this.refreshData(); } refreshData() { const startIndex = this.pageIndex * this.pageSize; const endIndex = startIndex + this.pageSize; // Apply search filter if a search query is entered const filteredData = this.searchInput ? yourDataArray.filter(item => item.column1.includes(this.searchInput) || item.column2.includes(this.searchInput) || item.column3.includes(this.searchInput) ) : yourDataArray; this.totalItems = filteredData.length; this.data = filteredData.slice(startIndex, endIndex); } onSearch(): void { this.pageIndex = 0; // Reset to the first page when performing a new search this.refreshData(); } }

HTML Template (your-component.component.html):

<div> <mat-form-field appearance="fill"> <input matInput [(ngModel)]="searchInput" placeholder="Search"> </mat-form-field> <button mat-raised-button color="primary" (click)="onSearch()">Search</button> </div> <mat-table> <!-- Define your table columns here --> </mat-table> <mat-paginator [length]="totalItems" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" (page)="onPageChange($event)"> </mat-paginator>

Summary:

  • Added a search bar (<mat-form-field>) and a search button (<button>) to the HTML template.
  • Added searchInput property to the component to store the search query.
  • Updated the refreshData function to apply a search filter to the data when a search query is entered.
  • Added an onSearch function to handle the search button click and refresh the displayed data based on the search query.
  • The pagination controls remain the same, and the search feature works alongside the pagination.

Angular Material Table – Sample Code to implement pagination


Here’s the sample code for implementing pagination in Angular using MatPaginator without MatTableDataSource, along with a summary:

Component Code (your-component.component.ts):

import { Component, OnInit, ViewChild } from '@angular/core'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html', styleUrls: ['./your-component.component.css'] }) export class YourComponent implements OnInit { displayedColumns: string[] = ['column1', 'column2', 'column3']; // Replace with your column names data: YourDataType[] = []; // Replace YourDataType with your data type pageSizeOptions: number[] = [5, 10, 25]; pageSize: number = 5; pageIndex: number = 0; totalItems: number = 0; @ViewChild(MatPaginator) paginator: MatPaginator; constructor() { } ngOnInit(): void { this.totalItems = yourDataArray.length; // Replace with the total number of items in your data array this.refreshData(); } onPageChange(event: PageEvent): void { this.pageSize = event.pageSize; this.pageIndex = event.pageIndex; this.refreshData(); } refreshData() { const startIndex = this.pageIndex * this.pageSize; const endIndex = startIndex + this.pageSize; this.data = yourDataArray.slice(startIndex, endIndex); } }

HTML Template (your-component.component.html):<mat-table> <!-- Define your table columns here --> </mat-table> <mat-paginator [length]="totalItems" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" (page)="onPageChange($event)"> </mat-paginator>

Summary:

  • The component sets up pagination with MatPaginator and handles changes to page size and index.
  • displayedColumns is an array of column names for your table.
  • data stores the current page of data.
  • pageSizeOptions defines the options for “Items per Page.”
  • pageSize and pageIndex control the current page size and index.
  • totalItems represents the total number of items in your data array.
  • @ViewChild(MatPaginator) allows access to the MatPaginator component in your HTML template.
  • onPageChange updates the page size and index when the user interacts with the pagination controls.
  • refreshData calculates which data to display based on the current page.

This code enables pagination in an Angular component using MatPaginator. Replace 'column1', 'column2', 'column3', YourDataType, and yourDataArray with your specific column names, data type, and data array.

Angular Material Table – refresh data when array is updated


Below is the reference –>

https://stackoverflow.com/questions/43404271/angular-2-view-not-updating-after-removing-elements-from-object-array

To summarize :

Add a #identifier to identify the material table html

<table mat-table [dataSource]="inputDataArray" class="mat-elevation-z8" #table1>

Create a @ViewChild() in the ts file to map to the MatTable and use renderRows() method to refresh the data in the table.

@ViewChild('table1') table:MatTable;

refresh(){
this.table.renderRows();
}

Angular make all div fit into the screen without scrollbar


Below is the reference from stackoverflow –>

https://stackoverflow.com/questions/30000515/how-to-make-all-div-fit-into-the-screen-without-scrollbar

So basically we need to set the below properties –>

display:flex;
flex-direction: column;
flex-wrap: wrap;

The display:flex will enable the flex. By default flex-wrap is set to nowrap. Setting this property to wrap will connect the child component to the main component without any need for scrollbar.

Angular DataBinding – Map textarea to [(ngModel)] binding


Below is the reference –>

https://stackoverflow.com/questions/37346820/ngmodel-for-textarea-not-working-in-angular-2

<textarea class="form-control" 
          name="message"
          rows="8"
          [(ngModel)]="Obj.message"
          #message='ngModel'
          ></textarea>

Adding the #message=’ngModel’ will allow us to map directly into component variable. Otherwise as mentioned in the stack overflow answer the textarea maps to JSON and we need to create the JSON before passing that to the textarea.

The attribute name="fieldName" is mandatory in the html. Otherwise it may not word as expected.

Databinding with conversions in Angular.


Check the below link :

Below are the steps –>

Create a getting and setter in the component.

get isActiveGroup() { return this.convertYNtoTrueFalse(this.alertGroup.actvInd);}

set isActiveGroup(input:boolean) { this.alertGroup.actvInd = this.convertTrueFalsetoYN(input);}

Map the isActiveGroup to ngModel in the html

<mat-checkbox name=”activeInd” [(ngModel)]=”isActiveGroup”>Active Indicator</mat-checkbox>

Please note the attribute name is Mandatory to be provided in html. Otherwise code will not work as expected.

Supporter Functions

convertYNtoTrueFalse(valueYN:string):boolean{
if(valueYN===”Y”){
return true;
}
return false;
}
convertTrueFalsetoYN(valueTrueFalse:boolean):string{
if(valueTrueFalse){
return “Y”;
}
return “N”;
}

Angular Notes Q&A


1. How to use angular component like a HTML Tag?
Use the component selector in the <></> braces

2. How to use the component like a html attribute?
In the selector setup selector with [] and use <div name></div>

3. How to use the component like a css class?
In the selector use “.selectorName” and in the div use <div class=”name”></div>

4. How to import bootstrap css into Angular?
Install bootstrap using the command npm – -save bootstrap
Then add the bootstrap css file name into the angular.json file. In the styles array add the bootstrap.min.css

5. What are the different ways in which databinding in Angular?
For String interpolation Use {{ componentAttribute }}
For property binding you can setup the property using [propertyName] = “componentAttribute”
For eventBinding use (eventName)=”methodInTheComponentClass”

6. What is two way data binding?
Two way databinding is a combination of property binding and event binding
[(ngModel)] =”componentAttribute”.
We need to import FormModules from angular/forms

7. What is directive?
Instructions from the angular server for the Dom manipulation

8. ngFor directive – Add html elements in a loop. Used to print the list of items in a loop into html.

9. ngStyle directive – Add component styles. Used to change the color to red if item is not available and green if an item of available.

10. ngIf directive – Add html elements only if a condition is True. In a shopping cart application this is used to create button to Notify if an item is not available. There is a else command which can set item to Buy Now when the item is available.

11. ngTemplate – create a template of code with a name starting with #. This template can be used in ngIf else command to display one of the two templates depending on the condition satisfaction.

12. ngClass – Set css class on an element dynamically based on a condition.

13. @Input – Custom Property binding to pass data from the parent component to the child component

14. @Output – Custom Property binding to pass data from child component to parent component

15. How to use @Input property?

Create a @Input() annotation on the child component to which the parent passes the attribute. In the html call of the parent where the child is called pass the property attribute.

16. How to use @Output property?

Create a @Output() attribute in the child component which will be passed to the parent. This needs to be of type EventEmitter<string> = new EventEmitter<string>() . Create a method in the child component which will run the attribute.emit() method and pass the value in the emit method. Then in the parent component html the child output attribute will be an event. Assign this event to a method with input parameter as String since we are passing a string as an output from the child component. You can you this output string in your main component.

17. What is template reference variable?

A dom element can be marked with with a # sign to indicate this as a template reference. This is used to trigger actions of the view element in the component ts file.

18. What is the use of @ViewChild decorator in Angular.

@ViewChild is used to get reference of any of the HTML references used in the page using a template reference variable. It is also used to access the child components of the parent component in the ts file.

19. What are the different ways in which we can perform View Encapsulation in Angular?

ViewEncapsulation.none – – No view Encapsulation. The css styles of the parent will be applied to the children if the names clash.

ViewEncapsulation.emulated – – Each element of the child component will create a unique name for the css classes so that css styles of parent and child to not clash. If mentioned in styles.css then that property will override whatever mentioned in the child class. This is an exception.

ViewEncapsulation.shadowDOM – – If the encapsulation property is set to shadow dom then that property will override whatever mentioned in styles.css. A separate dom is generated for the component ensuring a complete view Encapsulation.