Real-time Data Synchronization with RxJS Observables in Angular
This challenge focuses on building a robust real-time data synchronization mechanism within an Angular application. You will implement a service that utilizes RxJS Observables to manage and broadcast changes to a collection of items, allowing multiple components to react to updates seamlessly. This is a fundamental pattern for creating dynamic and responsive user interfaces.
Problem Description
You need to create an Angular service, DataSyncService, that manages a collection of Item objects. This service should expose an Observable that emits the current state of the entire collection whenever any item is added, updated, or removed. Components can subscribe to this Observable to stay updated with the latest data without manual polling.
Key Requirements:
ItemInterface: Define anIteminterface with at least anid(number, unique) and aname(string) property.DataSyncService:- Maintain an internal array of
Itemobjects. - Provide methods to:
addItem(item: Item): Adds a new item to the collection.updateItem(item: Item): Updates an existing item in the collection by itsid.removeItem(id: number): Removes an item from the collection by itsid.getItems(): Observable<Item[]>: Returns an Observable that emits the current state of the entireItemcollection.
- Ensure that each modification operation (add, update, remove) triggers a new emission from the
getItems()Observable.
- Maintain an internal array of
- Component Interaction: Demonstrate how a component can subscribe to the
getItems()Observable and display the data. It should also be able to trigger modifications through theDataSyncService.
Expected Behavior:
- When
addItemis called, the Observable emitted bygetItems()should include the new item. - When
updateItemis called with a matchingid, the corresponding item in the collection should be updated, and the Observable should emit the modified collection. - When
removeItemis called with a matchingid, the item should be removed, and the Observable should emit the updated collection. - Multiple components subscribing to
getItems()should all receive the same updates simultaneously.
Edge Cases:
- Attempting to update or remove an item that does not exist (based on
id). These operations should ideally be silent or provide feedback if necessary (though for this challenge, simply not performing the action is acceptable). - Adding an item with an
idthat already exists. For simplicity, assume unique IDs are provided or handle this case by rejecting duplicate IDs.
Examples
Example 1: Basic Add and Subscribe
// In DataSyncService
const service = new DataSyncService();
service.getItems().subscribe(items => console.log('Current items:', items)); // Initial emission will likely be empty
const newItem = { id: 1, name: 'Apple' };
service.addItem(newItem);
// Expected console output after addItem: Current items: [ { id: 1, name: 'Apple' } ]
const anotherItem = { id: 2, name: 'Banana' };
service.addItem(anotherItem);
// Expected console output after addItem: Current items: [ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' } ]
Example 2: Update and Remove
// Assuming DataSyncService is already populated as in Example 1
// Update
const updatedItem = { id: 1, name: 'Red Apple' };
service.updateItem(updatedItem);
// Expected console output after updateItem: Current items: [ { id: 1, name: 'Red Apple' }, { id: 2, name: 'Banana' } ]
// Remove
service.removeItem(2);
// Expected console output after removeItem: Current items: [ { id: 1, name: 'Red Apple' } ]
Example 3: Handling Non-existent IDs
// Assuming DataSyncService is populated with { id: 1, name: 'Grape' }
// Attempt to update non-existent item
const nonExistentUpdate = { id: 99, name: 'Watermelon' };
service.updateItem(nonExistentUpdate);
// Expected console output: No change. The Observable should emit the current state: [ { id: 1, name: 'Grape' } ]
// Attempt to remove non-existent item
service.removeItem(100);
// Expected console output: No change. The Observable should emit the current state: [ { id: 1, name: 'Grape' } ]
Constraints
- The
idproperty of anItemmust be unique within the collection. - All operations (add, update, remove) must be synchronous within the service.
- The
getItems()Observable must be a "hot" Observable (meaning multiple subscribers share the same underlying execution).BehaviorSubjectis a good candidate. - The solution should be implemented in TypeScript.
Notes
- Consider using
BehaviorSubjectfrom RxJS. It's ideal for managing a current value and emitting it to new subscribers. - Think about how to efficiently find and modify items within the internal array.
- You'll need to create a simple Angular component to demonstrate the subscription and interaction with the service. The focus is on the service and observable pattern, so the component UI can be very basic.
- The
getItems()observable should always emit a new array instance when changes occur, even if the contents are the same (e.g., if an update operation results in no visible change to the array structure but the item's properties are modified). This helps RxJS's change detection mechanisms.