You will see many articles on the internet about one field data filter which is filtering data based on your typed terms. In this tutorial, we are going to build something more advanced. It will be a multi-field data filter which will include simple inputs as well as selects. Let’s get started.
1. Creating a New Project
Let’s create a new project
2. Creating a Filter Pipe
We need to create a filter pipe in the first place. The pipe is a simple way to transform values in an Angular template.
3. Creating a Search Component
To get started, use the below command:
The last part for this component is implementing the search function:
To begin, enter the following command:
So we need to create a simple HTML table for displaying the data.
5. Creating a User Component
To start, use the below command:
User components will be a container for our search and user-list components.
While it's a general Angular topic, you can choose your desired way to make the above components work together. However, for this tutorial, this approach was used:
For the full working example you can visit here: github.com
1. Creating a New Project
Let’s create a new project
ng new angular-data-filters
cd angular-data-filtersWe also need to install a Bootstrap in Angular.
npm install bootstrapTo make it work in an Angular project, we need to add:
"node_modules/bootstrap/dist/css/bootstrap.min.css",inside the style section of the Angular.json file.
2. Creating a Filter Pipe
We need to create a filter pipe in the first place. The pipe is a simple way to transform values in an Angular template.
ng generate pipe filterAfter adding a couple of lines, we get our pipe to look like this:
import { Pipe, PipeTransform } from '@angular/core';It’s important to note that if all fields are empty the data should not be filtered.
@Pipe({
name: 'filter',
})
export class FilterPipe implements PipeTransform {
transform(items: any[], value: string, prop: string): any[] {
if (!items) return [];
if (!value) return items;
return items.filter(singleItem =>
singleItem[prop].toLowerCase().startsWith(value.toLowerCase())
);
}
}
3. Creating a Search Component
To get started, use the below command:
ng generate component searchLet’s create a simple form that will include inputs for the first name, last name, job title, gender, and age from and age to fields. The last two fields will be used to create an age range.
export class SearchComponent implements OnInit {search.component.html
form: FormGroup;
@Output() autoSearch: EventEmitter<string> = new EventEmitter<string>();
@Output() groupFilters: EventEmitter<any> = new EventEmitter<any>();
searchText: string = '';
constructor(private fb: FormBuilder,
private userService: UserService) {}
ngOnInit(): void {
this.buildForm();
}
buildForm(): void {
this.form = this.fb.group({
firstName: new FormControl(''),
lastName: new FormControl(''),
jobTitle: new FormControl(''),
gender: new FormControl(''),
agefrom: new FormControl(''),
ageto: new FormControl('')
});
}
<form novalidateYou might notice from the above code that we didn’t use a template-driven form which is provided by Angular. In this tutorial, we used reactive forms. Now it’s time to add a code block for the search component in the TS file.
[formGroup]="form">
<h3>Group Filter</h3>
<div class="row">
<div class="col-md-3">
<input type="text"
formControlName="firstName"
class="form-control"
placeholder="First Name"
/>
</div>
<div class="col-md-3">
<input type="text"
formControlName="lastName"
class="form-control"
placeholder="Last Name"
/>
</div>
<div class="col-md-3">
<input type="text"
formControlName="Job Title"
class="form-control"
placeholder="Job Title"
/>
</div>
<div class="col-md-3 col-sm-3">
<select class="form-control"
formControlName="gender">
<option value="">Gender</option>
<option value="M">male</option>
<option value="F">female</option>
</select>
</div>
<div class="col-md-3">
<input type="text"
formControlName="agefrom"
class="form-control"
placeholder="age from"
/>
</div>
<div class="col-md-3">
<input type="text"
formControlName="ageto"
class="form-control"
placeholder="age to"
/>
</div>
<div class="col-md-3 col-sm-3">
<button class="btn btn-primary"
(click)="search(form.value)">Search</button>
</div>
</div>
The last part for this component is implementing the search function:
search(filters: any): void {4. Building a User-List Component
Object.keys(filters).forEach(key => filters[key] === '' ? delete filters[key] : key);
this.groupFilters.emit(filters);
}
To begin, enter the following command:
ng generate component user-listWe will do it in the same way as we did for the search component, but, before that, we need data which will be fetched and displayed on the page. We are going to use JSON data that will add in the separate file and fetch it via a user service that will create with the following command.
ng generate service userHere is where Angular observables com ein to solve our problem.
export class UserService {add class User
setGroupFilter$ = new Subject<any>();
getGroupFilter = this.setGroupFilter$.asObservable();
constructor() {}
fetchUsers(): Observable<any> {
return of(USERS);
}
}
export const USERS = [After making changes inside user service we can start working on the User-list component (UserListComponent).
{
firstName: 'Sara',
lastName: 'Barnett',
level: 'Beginner',
jobTitle: 'UI Designer',
age:'18'
},
{
firstName: 'Gabriel',
lastName: 'Green',
level: 'Expert',
jobTitle: 'JS Developer',
age:'25'
},
{
firstName: 'Janet',
lastName: 'Cox',
level: 'Beginner',
jobTitle: 'Front-end Developer',
age:'45'
},
{
firstName: 'Frank',
lastName: 'Murray',
level: 'Expert',
jobTitle: 'Entrepreenur',
age:'67'
},
{
firstName: 'Olivia',
lastName: 'Peterson',
level: 'Beginner',
jobTitle: 'Blogger',
age:'37'
},
{
firstName: 'Tyler',
lastName: 'Rice',
level: 'Expert',
jobTitle: 'Accountant',
age:'28'
}
];
export class UserListComponent implements OnChanges {In the above code, we include event emitters in the search component and also get the data from the user service. Then we implement a user data filtering feature based on options like the age range or gender and by other filters as well. The most important thing is that you can type in both uppercase and lowercase and it will work in both cases. Sometimes you might notice issues connected with character type in the other examples.
@Input() groupFilters: Object;
@Input() searchByKeyword: string;
users: any[] = [];
filteredUsers: any[] = [];
constructor(private userService: UserService,
private ref: ChangeDetectorRef) { }
ngOnInit(): void {
this.loadUsers();
}
ngOnChanges(): void {
if (this.groupFilters) this.filterUserList(this.groupFilters, this.users);
}
filterUserList(filters: any, users: any): void {
this.filteredUsers = this.users;
const keys = Object.keys(filters);
const filterUser = user => {
let result = keys.map(key => {
if (!~key.indexOf('age')) {
if(user[key]) {
return String(user[key]).toLowerCase().startsWith(String(filters[key]).toLowerCase())
} else {
return false;
}
}
});
result = result.filter(it => it !== undefined);
if (filters['ageto'] && filters['agefrom']) {
if (user['age']) {
if (+user['age'] >= +filters['agefrom'] && +user['age'] <= +filters['ageto']) {
result.push(true);
} else {
result.push(false);
}
} else {
result.push(false);
}
}
return result.reduce((acc, cur: any) => { return acc & cur }, 1)
}
this.filteredUsers = this.users.filter(filterUser);
}
loadUsers(): void {
this.userService.fetchUsers()
.subscribe(users => this.users = users);
this.filteredUsers = this.filteredUsers.length > 0 ? this.filteredUsers : this.users;
}
}
So we need to create a simple HTML table for displaying the data.
<table class="table table-responsive">We have done a lot of work so far. Don’t worry, there's just a few steps left.
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Gender</th>
<th>Job Title</th>
<th>Age</th>
</tr>
<tbody>
<tr *ngFor="let user of filteredUsers | filter: searchByKeyword: 'name'">
<td>{{ user.firstName}}</td>
<td>{{ user.lastName}}</td>
<td>{{ user.gender}}</td>
<td>{{ user.jobTitle}}</td>
<td>{{ user.age}}</td>
</tr>
</tbody>
</table>
5. Creating a User Component
To start, use the below command:
ng generate component userYou might think, 'what’s the point of adding user components if there is already a user-list component included?'
User components will be a container for our search and user-list components.
<div class="container">Also, don't forget about user-routing.module.ts and user.module.ts
<br/>
<h1>List of Users</h1>
<hr/>
<app-search (groupFilters)="filters = $event"></app-search>
<br/>
<app-user-list [groupFilters]="filters"
[searchByKeyword]="searchText"></app-user-list>
</div>
While it's a general Angular topic, you can choose your desired way to make the above components work together. However, for this tutorial, this approach was used:
import { RouterModule, Routes } from '@angular/router';You can keep this two files inside the user folder.
import { UserComponent } from './user.component';
const routes: Routes = [
{ path: '', component: UserComponent }
];
export const UserRoutes = RouterModule.forChild(routes);
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { UserComponent } from './user.component';
import { SearchComponent } from '../search/search.component';
import { UserListComponent } from './user-list/user-list.component';
import { UserService } from '../../services/user.service';
import { FilterPipe } from '../../pipe/filter.pipe';
import { UserRoutes } from './user-routing.module';
@NgModule({
imports: [ CommonModule, FormsModule, ReactiveFormsModule, UserRoutes ],
declarations: [ UserComponent, SearchComponent, UserListComponent, FilterPipe ],
providers: [ UserService ]
})
export class UserModule { }
For the full working example you can visit here: github.com
No comments:
Post a Comment