I'm trying to understand how to pass data between components In Angular 2 using Observables/Services/Models and have the components update themselves once a change occurs. I don't know how to tie it all together or what the best practice to do so is.
Below is a scenario I have that deals with CRUD operations.
Goals:
use a RESTful API (w/Observables)
issue (API?) calls from child/sibling/parent components
have parent/sibling/child components update themselves automatically once a change occurs
Here's a visual of the component tree:
----------------
| Component A |
| Vehicle View |
----------------
/ \
/ \
---------------- ----------------
| Component B | | Component C |
| Vehicle List | | Vehicle Menu |
| REST: GET | | |
---------------- ----------------
/ / \
/ / \
------------------- ------------------------ -------------------
| Component D | | Component E | | Component F |
| Add New Vehicle | | Update Vehicle Name | | Delete Vehicle |
| REST: POST | | REST: PUT | | REST: DELETE |
------------------- ------------------------ -------------------
Component A
Component B
displays a list of vehicle (REST API: GET)
UPDATES: Component C ->[E,F] when a vehicle is selected
Component D
creates a new vehicle object/model (REST API: POST)
UPDATES: Component B (which then triggers Component B updates)
Component C
displays selected vehicle menu (vehicle name, delete selected vehicle)
UPDATES: Component E,F
Component E
Display/Edit selected vehicle Name (REST API: PUT)
UPDATES: Component B
Component F
Deletes selected vehicle (REST API: DELETE)
UPDATES: Component B + (to an extent updates) Component C since there's no more selected vehicle
I've seen/read/watched tutorials on Observables/Service/Components/Models but they have all been simple parent/child or single component examples. What I'm after is how to pass data through different branches and sibling leafs. How can a component leaf from one end of the tree trigger an update on a completely separate component branch/leaf.
I'm after either:
A tutorial (that I've missed) that already exists that covers all the CRUD operations in a similar scenario as above
a plunker that someone is willing to create to cover all the CRUD operations in the above scenario
theory on how to achieve the above (although, I want to say I understand the theory behind it but I'm having trouble putting it in practice)
For passing the data from the child component to the parent component, we have to create a callback function in the parent component and then pass the callback function to the child component as a prop. This callback function will retrieve the data from the child component.
Conclusion. In this article, we introduced three ways to communicate components with angular. A component related to one level, like a parent to a child using the input and output decorators, works fine.
Observable
s are just objects where you can subscribe to new data and emit new data to subscribers.
Observable
s aren't involved in what can communicate to what. This is what Angular DI and services are for. You can use services to share observables with a specific set of components.
Angular creates a hierarchy of injectors that resembles your component and directive tree. Each injector has a set of providers (the services that are registered with a component using providers: [...]
in the component or directive decorator (or bootstrap(AppComponent, [...] which is a parent of the root components injector).
DI maintains a single instance of a service (or other injectable) per provider. If a component depends on a service, DI starts looking for a provider at the component where it is required. If it can't find one it continues searching on the parent injector until it finds one or until it reaches the root injector.
This allows you to specify a scope of a service. If you provide it in bootstrap()
or the root component, the scope of this service is the whole application. If you provide it at another component, the scope is this component and its children.
If you want to communicate between to specific components, then provide a shared service at a common parent and inject it (add it to the constructor parameter list) to the components that should communicate with each other. You can see such a shared service as service bus.
The consumers of events subscribe to observables available in this shared service, the senders use the observable to emit data to subscribers.
@Injectable()
class VehicleService {
verhicles = new Subject();
createVehicle(newVehicle) {
return http.post(...)... // persist new vehicle
this.vehicles.emit(newVehicle);
}
updateVehicle(modifiedVehicle) {
return http.post(...)... // persist modified vehicle
this.vehicles.emit(modifiedVehicle);
}
...
}
@Component({
selector: 'my-app',
providers: [VehicleService], // provide globally
...})
export class AppComponent {}
@Component({
selector: 'b-cmp',
...})
export class ComponentB {
constructor(private vehicleService:VehicleService) {
vehicleService.vehicles.subscribe(data => {
// do something with new data
});
}
}
@Component({
selector: 'd-cmp',
...})
export class ComponentD {
constructor(private vehicleService:VehicleService) {}
persisteNew(vehicle) {
this.vehicleService.createVehicle(vehicle);
}
}
@Component({
selector: 'c-cmp',
...})
export class ComponentC {
constructor(private vehicleService:VehicleService) {}
saveVehicle(vehicle) {
this.vehicleService.updateVehicle(vehicle);
}
}
This just shows the very basics, but the full functionality would be way to broad for a SO answer.
https://github.com/ngrx/store might be insteresting for your use case which makes it easier to centrally manage all updates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With