https://github.com/leolanese/angular-forms-performance-fetch-search-filtering
Angular forms performance, search and filtering project
https://github.com/leolanese/angular-forms-performance-fetch-search-filtering
angular angular-components reactive-forms rxjs signal stand-alone template-driven-form typescript
Last synced: 3 months ago
JSON representation
Angular forms performance, search and filtering project
- Host: GitHub
- URL: https://github.com/leolanese/angular-forms-performance-fetch-search-filtering
- Owner: leolanese
- Created: 2024-04-02T18:07:52.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-05-04T08:31:12.000Z (8 months ago)
- Last Synced: 2025-05-04T09:27:09.666Z (8 months ago)
- Topics: angular, angular-components, reactive-forms, rxjs, signal, stand-alone, template-driven-form, typescript
- Language: TypeScript
- Homepage:
- Size: 1.05 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Angular (20+) Signal Power: Angular Forms, Search & Filter Performance Lab
- This project serves as a comprehensive demonstration of Angular's flexibility in implementing the same core functionality through different patterns and approaches, each with its own trade-offs in terms of complexity, maintainability, and performance.
---
## Demo
- Score

- Winner example 14 - Pure Signal-Based Architecture

---
## Evaluation Criteria
- Modern Angular best practices (Signals, Standalone Components, RxJS, etc.)
- Performance (reactivity, change detection, memory)
- Maintainability (readability, modularity, testability)
- Scalability (how well it would work in a larger app)
- Follows new modern Angular trends
---
## Resoltion Solution evaluations
### Solutions 1–5: Classic RxJS & Forms Approaches
| Solution | Approach | Rating | Notes |
|----------|----------|--------|-------|
| 1 | Template-driven forms, RxJS, filter pipe, manual subscription mgmt | 1 | Outdated, verbose, not idiomatic for modern Angular. |
| 2 | Template ref variable, RxJS, filter pipe | 1 | Slightly better, but still not scalable or modern. |
| 3 | Reactive Forms, RxJS, filter pipe | 2 | More modern, but relies on pipes and manual RxJS. |
| 4 | Material input, Reactive Forms, RxJS, filter pipe | 2 | Good for Material projects, but not leveraging Signals. |
| 5 | Reactive Forms, RxJS, filter pipe | 2 | Clean, but not as modern as Signals-based solutions. |
### Solutions 6–9: Hybrid RxJS + Signals
| Solution | Approach | Rating | Notes |
|----------|----------|--------|-------|
| 6 | Reactive Forms, RxJS, toSignal, filter pipe | 2 | Starts using Signals, but still hybrid and not full Signals. |
| 7 | Like 6, but optimizes for stable values | 2 | Slightly better, but still hybrid. |
| 8 | Template-driven, Signals, RxJS, filter pipe | 2 | Uses Signals, but not fully idiomatic. |
| 9 | Template-driven, Signals, RxJS, filter pipe | 2 | Similar to 8, not fully leveraging Signals' power. |
### Solutions 10–11: Component-Driven, RxJS, and Modular
| Solution | Approach | Rating | Notes |
|----------|----------|--------|-------|
| 10 | Reactive Forms, RxJS, combineLatest, modular | 2 | Good modularity, but not using Signals. |
| 11 | Component-driven (filter, sort, pagination), RxJS, modular | 2 | Very modular, but not using Signals. Good for classic Angular. |
### Solutions 12–13: Hybrid Signals, Modern trendy Angular
| Solution | Approach | Rating | Notes |
|----------|----------|--------|-------|
| 12 | Component-driven, full Signals (computed, effect, toSignal), modular | 3 | Modern, scalable, maintainable, highly recommended. |
| 13 | Hybrid Signals (signal, computed, effect), modular, idiomatic | 3 | Mostly Remmended: idiomatic, performant, future-proof, best for new Angular projects. |
### Solutions 14: Pure Signals, Modern trendy Angular
| Solution | Approach | Rating | Notes |
|----------|----------|--------|-------|
| 14 | Pure Signal-Based Architecture | 3 | Remmended: idiomatic, performant, future-proof, trendy, follow Angular best practices and best for new and future Angular projects. |
---
## Overall Project Goals
- Demonstrate different approaches to implement the same search functionality in Angular
- Compare various Angular patterns and best practices
- Show evolution from simple to complex implementations
- Warning Spoil: Solution13 is the recommendation!
## Form Handling Approaches
- Template-driven forms (Solutions 1, 8, 9)
- Reactive forms (Solutions 3, 4, 10)
- Manual event handling (Solution 2)
- Component-driven forms (Solution 11)
## Simple State:
- Two-way binding (Solution 1)
- Template reference variables (Solution 2)
- FormControl direct binding (Solution 3)
## Advanced State:
- Signals (Solutions 6, 7, 8, 9, 13)
- RxJS Streams (Solutions 10, 11)
## Pure Signal Solution: Component + Service (httpResource instead httpClient):
- Fully signal-based (Solution 13)
- This is using Angular 19.2+ new "httpResource()" API which is designed to work with signals and provides automatic state management for HTTP requests.
- The `httpResource` provides built-in signals:
+ value for the data
+ isLoading for loading state
+ error for error state
- Main features:
+ Automatic Reactivity
+ Default state
+ Data validation and transformation
## Extra Aditional API notes:
- Filtering: The end-point is already filtering depending on the user-input, but including the filter pipe in our template (countries$ | async | filter:searchFilter), Angular will apply the FilterPipe's transform method to the countries$ observable's emitted values. This means, that each time the countries$ observable emits a new array of countries, Angular will filter those (can be multiple) countries based on the searchFilter string using the logic defined in the FilterPipe. To test: input `UK` it should return only `Ukraine` then check for the console. You must see: `Filter pipe triggered: true` once
---
## Conclusion
- `Solutions 1–5` are not recommended for new projects.
- `Solutions 6–11` are transitional or modular, but not as modern as full Signals-based approaches.
- `Solution 13` is the most recommended, followed closely by `Solution 12`. Both use Angular Signals throughout, are modular, and align with the latest Angular best practices and trends for 2024 and beyond.
- `Solution 14` is the the recommended, followed closely by `Solution 14`. This align with 2025 best practices and recommendations.
---
## Individual solutions explanation
1) ✅ Uses:
- Template-driven forms with [(ngModel)] 2-way binding with ngModelChange
- Custom pipe filtering with filter pipe
- RxJS with takeUntilDestroyed pattern
- Reactive search with debounceTime and distinctUntilChanged
2) ✅ Uses:
- Template reference variables (#searchBox)
- Event binding with (input)
- Custom pipe filtering with filter pipe
- RxJS with takeUntilDestroyed pattern
- Reactive search with debounceTime and distinctUntilChanged
- Manual state management for search text
3) ✅ Uses:
- Reactive forms with FormControl and FormGroup
- Direct FormControl binding with [formControl]
- Custom pipe filtering
- RxJS with startWith and takeUntilDestroyed
- valueChanges observableformControl (directly binding the FormControl instance)
4) ✅ Uses:
- Material UI components
- Reactive forms with formControlName
- Custom pipe filtering with slice
- RxJS subscription management
- Typed form controls with interfaces formControlName (directly bind to specific - - input element within the template)
- .get()
5) ✅ Uses:
- pipe Ng2SearchPipeModule for filtering
- Reactive forms with formControlName
- RxJS with takeUntilDestroyed
- Null safety with optional chaining
- RxJS error handling with map
6) ✅ Uses:
- Angular Signals with toSignal
- Reactive forms with FormGroup
- Effects for signal monitoring
- Custom pipe filtering
- RxJS with startWith and takeUntilDestroyed
7) ✅ Uses:
- Signals with toSignal (based on stable values & optimise for efficient rendering)
- Reactive forms with FormGroup and formControlName
- Custom pipe filtering
- RxJS with debounceTime and takeUntilDestroyed
- Optimized for efficient rendering
8) ✅ Uses:
- Template-driven forms with [(ngModel)]
- Signals with signal, computed, and effect
- ViewChild for form access
- Custom pipe filtering
- Manual `onSearch` trigger with button
9) ✅ Uses:
- Template-driven forms with [(ngModel)]
- Signals with signal
- Simplified state management
- Custom pipe filtering
- Manual search trigger with button
- DestroyRef for cleanup
10) ✅ Uses:
- Reactive forms with validation
- FormBuilder service
- RxJS combineLatest for data streams
- Mock data with static countries
- Form validation error messages
- RxJS operators (startWith, distinctUntilChanged)
(based on https://github.com/leolanese/Angular-rxjs-filtering-list)
11) ✅ Uses:
- Component-driven architecture
- Separate components for Filter, Sort, List, and Pagination
- Advanced RxJS stream management
- FormBuilder with reactive forms
- Comprehensive data handling (filter, sort, paginate)
- SearchService integration
- Smart and presentational component pattern
12) ✅ Uses:
- Moving to pure signal
- Signal-based form value tracking
- Signal-based state management
- signal() for writable state, computed() Computed values for filtering, sorting, and pagination, effect() for side effects, toSignal() for converting RxJS
- Automatic dependency tracking between signals
- Performance optimization through Signal-based reactivity
- Reactive forms with FormGroup and FormControl (avoiding continuous re-evaluations caused by traditional getters)
- Component composition (reusing Solution11's child components)
> This represents a modern Angular implementation using Signals instead of RxJS Observables for state management, while maintaining the component-driven architecture from Solution 11.
13) ✅ Uses:
### Signal State Management
✔ Uses a single state signal to manage all application state
### Signal Data Flow
✔ Manages all state through signals
✔ Uses computed signals for derived data
✔ Handles data transformation (filtering, sorting, pagination)
✔ Communicates with the service layer
## Signal Child Components communication
✔ SignalFilterComponent: Two-way binding with model() for filter text
✔ SignalSortComponent: Two-way binding with model() for sort direction
✔ SignalListComponent: Signal-based input for countries list
✔ SignalPaginationComponent: Two-way binding with model() for current page
## Signal Service Layer communication
✔ SignalCountryService uses signals for: Data fetching, Loading states, Error handling
> Solution13 represents a modern, fully signal-based Angular application with: Clean architecture, Efficient state management, Type-safe components, Reactive data flow, Optimised performance, Clear separation of concerns, which is more efficient than traditional change detection and provides better developer experience.
## Further explanation `Solution13 as fully signal-based`
### Singal state management
```js
// Base signals for state
filterText = signal('');
sortDirection = signal<'asc' | 'desc'>('asc');
currentPage = signal(0);
```
### Computed Signals for derived state:
```js
filteredCountries = computed(() => {
const countries = this.countryService.getCountries().data();
const filter = this.filterText().toLowerCase();
// ... filtering logic
});
sortedCountries = computed(() => {
const countries = this.filteredCountries();
// ... sorting logic
});
totalCount = computed(() => this.sortedCountries().length);
totalPages = computed(() => Math.ceil(this.totalCount() / this.itemsPerPage));
```
### Effects (for side effects)
```js
effect(() => {
// Reset page when filter or sort changes
this.currentPage.set(0);
}, { allowSignalWrites: true });
```
### Signal-based Service
```js
export class SignalCountryService {
private countries = signal([]);
private isLoading = signal(false);
private error = signal(null);
// ...
}
```
### Signal-based Components
```js
// In SignalFilterComponent
filterValue = model.required();
// In SignalListComponent
countries = input.required();
```
---
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17+
```js
ng new Angular-Search-Filtering
npm i
npm i bootstrap
```
```js
// package.json
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss"
]
```
```js
ng g s services/country
// later on exploring the Entity Pattern
ng g p pipes/filter
// reusable pipe to filter array based on search term
```
## API Service
We are using "https://restcountries.com" sometimes these services are not as fast as expected, I'm looking forward to replace (maybe with: https://countries.petethompson.net) it but for now it's good enough.
---
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
---
### :100: Thanks!
#### Now, don't be an stranger. Let's stay in touch ‼
##### :radio_button: gitroll: LeoLanese
##### :radio_button: Linkedin: LeoLanese
##### :radio_button: Twitter: @LeoLanese
##### :radio_button: Blog: Blog/a>
##### :radio_button: Questions / Suggestions / Recommendations: developer@leolanese.com