Angular Material Table With Search by Query Params Using Node JS API (Learn it in 28 Steps includes…

Angular Material Table With Search by Query Params Using Node JS API (Learn it in 28 Steps includes…

Please find the below steps to show the angular material table with filters and node js API and apply search and filter in angular application.

  1. Create an angular project with the below command.

ng new angular-material-table-filter-search-and-query-params

2. After successful creation of the angular app, change file directory to project-name. “cd angular-material-table-filter-search-and-query-params”

Open the project in vs code using “code .” in terminal or open with vs code. Then run the project using “ng serve” in the terminal. Open project in chrome using ***localhost:4200***

3. Open the app component in vs code and remove the content which is created by angular CLI while creating the app.

**For Adding angular material using the command

ng add @angular/material**

4. Select theme, Am selecting Indigo/Pink, and click the below items as “yes

  • Set up global Angular Material typography styles? Am selecting y
  • Set up browser animations for Angular Material? (Y/n) Select ‘y’.

5. Created Shared Module in the libs folder using “ng generate module shared”. And import, and export material modules in “shared.module.ts”. And also add in the app.module.ts

shared.module.ts

6. Create the Audits component in the “apps/components” folder. And add audits component in router and path as audits. Run the project by using “ng serve” and open the audits component by using “localhost:4200/audits” in the browser address bar.

7. In side “audits.component.ts” file creates a variable for displaying columns as below and also creates the total count variable.

public displayedColumns: any =["uri",'email',"clientIp",'client_org',"serverIp",'server_org',"statusMessage","createdAt","updatedAt"]
public totalCount=0;

8. For calling API requests from audits.component.ts to get audit records created one method i.e. this.getUsers(0,10) and call this method from ngOnInit().

public ngOnInit():void{
this.getAudits(0,5)
}

**public getAudits(pageIndex,pageSize){

}**

9. Create an audit-service file in the “app/apis” folder by using the below command. Add service as a dependency in audits.component.ts

ng generate service audit-service

10. Create service method getAudits(pageIndex,pageSize, filter?) inside the service file and call the backend endpoint to retrieve the audit details based on pageIndex, pageSize and filter will be optional.

**public headers:HttpHeaders= new HttpHeaders({
'Content-Type':'application/json',
'Accept':"application/json",
'Access-Control-Allow-Methods':'GET,POST,PUT,DELETE',
'Authorization':''
});

constructor(private http:HttpClient) { }**

public getAudits(pageIndex,pageSize, filter?){

let params= new HttpParams();
if(filter){
if(filter.statusCode){
params = params.append('statusCode', filter.statusCode);
}
if(filter.statusMessage){
params = params.append('statusMessage', filter.statusMessage);
}
if(filter.email){
params = params.append('email',filter.email);
}
}

return this.http.get(`localhost:3000/public/audits/${pageIndex}/${pageSize}`,{headers :this.headers, params})

}

11. Call this above service method from the audits.component.ts file and to test add console.log.

public getAudits(pageIndex,pageSize){
this.audit.getAudits(pageIndex,pageSize, formValues).subscribe((res: any)=>{
console.log(res);
},
error=>{
console.error(error.message);
})
}

12. After that create the datasource variable, also create the model file under the app/models folder, and export the Audit Entry Interface. Add the audit entry as an import statement in side audits.component.ts and give the data source type as AuditEntry[].

export interface AuditEntry{
clientIp: string;
clientIpDetails: IpDetails[]
createdAt: any;
email: string;
hostname: string;
serverIp: string;
serverIpDetails: IpDetails[];
statusCode: string | number;
statusMessage: any;
updatedAt: any;
uri: any;
_id: string | number;
}

export interface IpDetails{
city: string;
country: string;
ip: string;
loc: any;
org: string;
postal: any;
readme: any;
region: any;
timezone: any;
_id: string | number
}

  • Import AuditService and AuditEntry entry inside audits.component.ts

import { AuditService } from 'src/app/apis/audit.service';
import { AuditEntry } from 'src/app/models/audit.model';

  • Update datasource type as AuditEntry[].

public dataSource: AuditEntry[];

13. Store the response in both datasource and total count as below.

public getAudits(pageIndex,pageSize){
this.audit.getAudits(pageIndex,pageSize, formValues).subscribe((res: any)=>{
this.dataSource = res.audits;
this.totalCount = res.totalCount;
},
error=>{
console.error(error.message);
})
}

14. Create variable paginator variable and give type as mat paginator and apply @viewchild on that variable, in that way you were able to access the entire element of mat-paginator.

import { MatPaginator, PageEvent } from '@angular/material/paginator';

15. Oops!!!, we have not added Html content. Add Html content for displaying the table.

  • set displayedColumns[] to two items e.g. [createdAt, updatedAt]

*




<th mat-header-cell \
matHeaderCellDef> CREATED AT
{{element.createdAt}}

        <ng-container matColumnDef="updatedAt">  
            <th mat-header-cell \*matHeaderCellDef> UPDATED AT  </th>  
            <td mat-cell \*matCellDef="let element"> {{element.updatedAt}} </td>  
        </ng-container>  

        <tr mat-header-row \*matHeaderRowDef="displayedColumns"></tr>  
        <tr mat-row \*matRowDef="let row; columns: displayedColumns;"></tr>  
    </table>  

**

  • After that add all the columns to displayedColumns[] and add Html related to columns inside the table. Test the UI in the browser for changes.

  • Add a paginator tag below the table to display page options for lazy loading. And create pageNavigate(page:PageEvent) method inside audits.component.ts add call the getUsers(pageIndex,pageSize).


  • Add pageNavigate() inside the audits.component.ts and call getAudits method.

public pageNavigate(event:PageEvent){
this.getAudits(event.pageIndex,event.pageSize);
}

Test the changes by running ng serve and open URI in browser “localhost:4200/audits”. You can able to see the page options and by clicking on the next page, you can able to see new records.

16. Add filter values endpoint in service to load the filter dropdowns in the audits.component.html file. Create getFilterValues() method to call the service method getAuditFilterValues() and call the getFilterValues() method from ngOnInit();

  • Add getAuditFilterValues() inside audit.service.ts file.

public getAuditFilterValues(){
return this.http.get(`
localhost:3000/public/audits/filter-values`,{headers :this.headers})
}

  • Create getFilterValues() and call the getFilterValues from ngOnInit().

ngOnInit():void{
this.getFilterValues();
this.getAudits(0,5)
}public getFilterValues(){
this.audit.getAuditFilterValues().subscribe((res: any)=>{
this.filterValues = res
},
error=>{
console.error(error.message);
})
}

17. Add form builder as a dependency in the constructor and create form, filter values variable, and formInit() to initialize form and create the form group, adding form controls inside form group. Store the response in the filter values variable.

public filterValues: any;

public form:FormGroup;

constructor(private fb: FormBuilder) {
this.formInit();
}

private formInit(){
this.form = this.fb.group({
statusCode:[''],
statusMessage:[''],
email:[''],
})
}

18. Oops!! Again not added HTML to display filter-dropdowns in audits.component.html, apply filter, and clear filter buttons. And also add apply Filter , clear filter functions inside audits.component.ts and call getAudits(0,10);






{{statusCode}}







{{statusMessage === 'OK' ? 'LOGIN SUCCESS' :'LOGIN FAILED'}}








{{email}}
Email Not Entered





Apply Filter


Clear Filter


public applyFilter(){
this.paginator.firstPage();
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}public clearFilter(){
this.form.reset();
this.paginator.firstPage();
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}

19. Add filter as a parameter in service method, create httpParams and append params to httpParams. Send form values from getAudits() to the service method.

public getAudits(pageIndex,pageSize, filter?){
let params= new HttpParams();
if(filter){
if(filter.statusCode){
params = params.append('statusCode', filter.statusCode);
}
if(filter.statusMessage){
params = params.append('statusMessage', filter.statusMessage);
}
if(filter.email){
params = params.append('email',filter.email);
}
}
return this.http.get(`
localhost:3000/public/audits/${pageIndex}/${pageSize}`,{headers :this.headers, params})
}

public getAudits(pageIndex,pageSize){
const formValues = this.form.getRawValue();
this.audit.getAudits(pageIndex,pageSize, formValues).subscribe((res: any)=>{
this.dataSource = res.audits;
this.totalCount = res.totalCount;
},
error=>{
console.error(error.message);
})
}

20. For testing the project using “ng serve” and open “localhost:4200/audits” in the browser and test by clicking page navigation, apply filter, and clear filter.

21. All done for the filter, Next am going to implement the search functionality to display audits based on the search text.

22. Create a search component under components/audits by using the below command.

ng generate component audit-search

23. Open the search component and add form builder as a dependency in the constructor, form group, and formInit() method. Also call formInit() method inside ngOnInit() like below.

  • Create a form variable and give the type as FormGroup.

public form:FormGroup;

  • Add form builder as a dependency in the constructor as below.

constructor(private fb:FormBuilder) { }

  • Initialize form with a form group and add searchText as form control in the side ngOnInit method.

public ngOnInit(): void {
this.form = this.fb.group({
searchText: ['']
})
}

24. Open audit-search.component.html and add below Html code with form group name and from control.





25. Add audit-search component selector inside audits component as below.

26. After that add @Output Directive (Event Emitter) inside the audit-search component to send data from the audit-search component to the audits component like below.

  • Add Output directive inside audit search component like below.

@Output() public auditSearch: any = new EventEmitter();

  • Add form.valueChanges method in side ngOnIt() to emit the event whenever the search value will change like below.

public ngOnInit(): void {
this.form = this.fb.group({
searchText: ['']
})

this.form.valueChanges.subscribe(value=>{
this.auditSearch.emit(value)
})
}

  • Add the auditSearch event inside the audit-search selector and also add the respective method inside the audits component like below. To store search value globally, create variable searchText and assign the value whenever an event is performed.

public auditSearch(value){
const search =value.searchText;
this.searchText = search;
this.paginator.firstPage();
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}

  • Change getAudits method implementation to satisfy the search functionality.

public getAudits(pageIndex,pageSize){
const formValues = this.form.getRawValue();
if(this.searchText){
formValues["searchText"] = this.searchText;
}
this.audit.getAudits(pageIndex,pageSize, formValues).subscribe((res: any)=>{
this.dataSource = res.audits;
this.totalCount = res.totalCount;
},
error=>{
console.error(error.message);
})
}

27. After adding event emitter and respective method. Add view child of the audit-search component inside the audits component to clear the search text.

@ViewChild(AuditSearchComponent, {static: false}) AuditSearchComponent: AuditSearchComponent;/*To Clear the search text value use this.auditSearchComponent.form.reset()
while performing apply filter*/
public applyFilter(){
this.auditSearchComponent.form.reset();
this.paginator.firstPage();
this.searchText = ''
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}public clearFilter(){
this.form.reset();
this.paginator.firstPage();
this.searchText = ''
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}

After all, this is done, do “npm install” and “ng serve” to run the application, And also run backend API with “npm run dev” if not started. open application with localhost:4200.

28. For Adding Query params, Nothing we need to update all the files just update the audits component itself. Open audits.component.ts, Import ActivatedRoute, Router, and add it as a dependency inside the constructor.

constructor(private audit:AuditService,private fb: FormBuilder, private route:ActivatedRoute, private cdr: ChangeDetectorRef,
private router:Router)
{
this.formInit();
}

29. Open the audits.component.ts file, Import ngAfterViewInit, and add the ngAfterViewInit() method inside the component for reading query params from the router. Also, update the ngOnInit method and patch the query param value to the search component form.

ngOnInit():void{
this.getFilterValues();
}

ngAfterViewInit():void{
this.route.queryParams.subscribe(params=>{
if(params && params?.searchText){
this.searchText= params?.searchText;
this.auditSearchComponent.form.patchValue({searchText:params?.searchText})
}
this.getAudits(0,5)
})
}

30. After doing the above point, update the auditSearch() method to update the URL whey user did search manually not from the URL.

public auditSearch(value){
this.router.navigate([], {
relativeTo: this.route,
queryParams: { searchText: value.searchText },
queryParamsHandling: 'merge',
skipLocationChange: false,
});

this.searchText = value?.searchText || '';
this.paginator.firstPage();
this.getAudits(this.paginator.pageIndex,this.paginator.pageSize);
}

31. After all is done, Then do npm install and ng serve. you will see the error in the console.

32. To Resolve the error, Am importing the AfterViewChecked life cycle event and ngAfterViewChecked() method inside the app.component.ts. Import ChangeDetectorRef and add it as a dependency inside the constructor. Also, add a statement inside the ngAfterViewChecked() method to resolve the error.

import { AfterViewChecked, AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';

constructor(private audit:AuditService,private fb: FormBuilder,
private route:ActivatedRoute,private cdr: ChangeDetectorRef,private router:Router) {
this.formInit();
}

ngAfterViewChecked(){
this.cdr.detectChanges();
}

33. After all this is done, Please do npm install and ng serve to run the application and open application in browser by using localhost:4200/audits

Output

output of query param search and filter

Source Code

Front End:
GitHub:
mryenagandula/angular-material-table-filter-search-and-query-params

Back End:
GITHUB:
github.com/mryenagandula/Letstalk-Backend

Live Backend URI: letstalk-be.herokuapp.com

Stack blitz Project Preview:

stackblitz.com/edit/angular-material-table-..

Thanks for reading my article, Please share your feedback, claps, and comments. In that way, it will be helped me to improve my articles in the future. Please share my story with your near and dear, Also follow and subscribe to the medium.