Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Architecture - how to pass data elements in complex component tree structure

Tags:

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

  • just encapsulates all the other components

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)

like image 937
Nik Avatar asked Jun 15 '16 16:06

Nik


People also ask

How do you pass data from one component to another component?

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.

How many ways we can pass data in angular?

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.


1 Answers

Observables are just objects where you can subscribe to new data and emit new data to subscribers.

Observables 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.

like image 172
Günter Zöchbauer Avatar answered Sep 27 '22 19:09

Günter Zöchbauer