https://github.com/leolanese/angular19-api-observable-signal
Angular (19+) Request API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)
https://github.com/leolanese/angular19-api-observable-signal
angular httpresource input input-signal observable resful-api rxjs signals
Last synced: about 1 year ago
JSON representation
Angular (19+) Request API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)
- Host: GitHub
- URL: https://github.com/leolanese/angular19-api-observable-signal
- Owner: leolanese
- Created: 2025-01-23T20:28:09.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-15T16:05:32.000Z (about 1 year ago)
- Last Synced: 2025-06-11T23:24:12.196Z (about 1 year ago)
- Topics: angular, httpresource, input, input-signal, observable, resful-api, rxjs, signals
- Language: TypeScript
- Homepage:
- Size: 1.09 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Angular (19.2+) Observable + Signals for handling API requests
π΄
π‘
π’
π
## βΊ Goals AC's
### βΊ Test legacy Angular Vs new modern Angular practices
Test API based on Observable, Signal (state management, effect, httpResource, input-pattern, model)
### βΊ Test simple/direct Api Request using a few API services:
https://jsonplaceholder.typicode.com/posts
https://swapi.dev/api/vehicles
### βΊ Test complex/nested API Requests
1. Get all country names and display on the page:
https://restcountries.com/v3.1/independent?fields=name
2. Select a country and Show the flag:
https://restcountries.com/v3.1/name/Grenada?fields=name,flags
3. Search countries by language:
https://restcountries.com/v3.1/lang/spanish?fields=name
---
## πΈ Demo

---
## πΈ Example Solution Arquitecture
```js
src/
βββ app/
βββ SoC/
βββ input/output // Separation of Concern using Parent and Child, @Input()/@Output()
βββ input/output // Separation of Concern using Parent and Child, input signal/@Output()
βββ orphan-observable/ // single Component, managing API request using Observables
βββ orphan-signal/ // single Component, managing API request using Signals
βββ orphan-signal-simple/ // single Component, managing API request using Signal
βββ orphan-signal-nested/ // single Component, managing complex API request using Signal
βββ orphan-signal-httpresource/ // simple Component, managing API request using Signals with httpResouce asynchronous data fetching
βββ orphan-signal--httpresource-reactiveForm/ // Shows how the new signals approach replaces the traditional RxJS pattern
βββ orphan-signal-httpresource-signal/ // 100% fully signal-based. Using direct signal binding with [value] and (input). Simple event handler to update the signal
βββ orphan-signal-input-pattern/ // full signal-based approach: 1-way binding
βββ orphan-signal-model/ // full signal-based approach: 2-way binding
|
βββ app.component.ts
βββ auth.interceptor.ts
βββ http.interceptor.ts
```
## πΈ Technical mentions
π‘ Green solutions are 100% fully reactive signal-based which are Angular recommendations:
π΅ Reactive state management
- `All state is managed through signals in the service`
π΅ Data Management:
- `No local component state variables` that aren't signals
- `No RxJS Observables or Subjects`
π΅ HTTP Handling:
- `Signal with httpresource`, for automatic data fetching
π΅ Template Binding:
- Replaces `NgModel` is part of the older Forms API, while signals represent Angular's future
- `All template expressions use signals` (vehicleService.searchTerm(), vehicleService.isLoading(), etc.)
- Uses `modern Angular control flow` (@if, @else, @for)
π΅ Data Flow:
### `Unidirectional Data Flow`:
```js
Signal β View ([property] binding) = [value]="searchSignal()
View β Signal (event() handler) = (input)="signal.set()"
```
- Use `signal-input-pattern`: `[value] + (input) pattern`:
`It's simply a combination of 1-way binding (Property [value]="searchSignal()" + event binding (input)="signal.set()")`
- `Direct Signal Control` (when is read = binding, when is updated = event handler)
### `Bidirectional Data Flow` (model() implement 2-way binding simplify two-way binding boilerplate
π΅ Event Handling:
- Input events directly update signals (this.vehicleService.searchTerm.set(value))
- No intermediate transformations using RxJS operators
π΅ Service Implementation:
- Uses httpResource for HTTP requests (instead HttpClient)
This provides:
- Automatically fetches data when the component initializes.
- Handles loading, success, and error states without extra code.
- Provides a .value() method to access the latest data.
- Supports reloading with .reload().
- Stays within the signals paradigm and use signals' effect() to automatically handle cleanup (instead OnInit/OnDestroy + No need for manual subscription management)
π‘ Other technical mentions
π΅ `SoC`
This example demonstrates the separation of concerns between the:
`service (responsible for fetching data)`,
`smart component (responsible for handling business logic and passing data to the dummy component)`, `dummy component (responsible for rendering the UI)`
π΅ `Modern StandAlone Components`:
I directly bootstrap the component itself, not its module. This is because standalone components have their own injectors and don't rely on a root module for dependency injection. Promotes code maintainability, reusability, and smaller application size.
π΅ Implemented `TSP mechanism`:
I'm using `Tree Shakeable Providers` in `Services` by using the `providedIn` attribute, this will provide the benefits of both `tree shaking performance` and `dependency injection`,
meaning that our services will not be included in the final bundle unless they are being used by other services or components. As a result we reduce the bundle size by removing unused code from the bundle.
π΅ `RxJS`
- `takeUntilDestroyed(this.destroyRef)` to automatically unsubscribe when the component is destroyed, simplifying the cleanup process even further
- `shareReplay(1)` because multiple components might subscribe to the same observable
π΅ `Dependency Injection Pattern`:
I'm using Modern `Dependency Injection functions`, instead traditional `constructor-based dependency injection`as result I will have a more Modular, Less Complex
π΅ Implement Caching:
-- `Cache API Service Calls`
Caches identical HTTP requests within a single component:
I'm using `shareReplay()` to improve efficiency, ensuring that all subscribers receive the most recent data without triggering multiple HTTP requests.
π΅ `DestroyRef & takeUntilDestroyed()`: Angular 16+
I'm using provides a more declarative and efficient way to handle automatic cleanup tasks when a component or service is destroyed: `takeUntilDestroyed(this.destroyRef)` to automatically unsubscribe when the component is destroyed, simplifying the cleanup process even further
π΅ `Function-based Interceptor` (optional):
It also showcases the usage of an interceptor to log HTTP requests and responses. While not necessary for this example, it can be useful for debugging and monitoring purposes (WIP)
---
### :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: dev.to/leolanese
##### :radio_button: Questions / Suggestions / Recommendations: developer@leolanese.com