mercredi 14 juillet 2021

Sharing data between components, within different "paths" / hierarcies

I have an app which is used by the employees of a repair shop to keep track of ongoing repairs.

The app has 3 components (AppComponent, ClientComponent and RepairComponent):

  • <AppComponent>: holds the "main / current" view of the app, which is simply one of the other two components rendered using <router-outlet>, plus a button which can dynamically load an instance of one of the two components (ClientComponent) within a dialog (MatDialog) instead of rendering it into <router-outlet>:
<a [routerLink]="['/new-client']">
    New client
</a>
<a [routerLink]="['/new-repair']">
    New repair
</a>

<router-outlet></router-outlet>

<button (click)="openClientPopup()">
    Add new client
</button>
  • <ClientComponent>: form used to add new clients:
<form>
    ...
</form>
  • <RepairComponent>: form used to add new repairs; this component can, much like AppComponent, also dynamically load an instance of ClientComponent within a dialog (MatDialog), so to make it easy to add a new client while in the process of creating a new repair:
<form>
    ...
</form>

...

<button (click)="openClientPopup()">
    Add new client
</button>

Now the problem I'm facing is:

  • AppComponent should be able to communicate with ClientComponent and RepairComponent through the router, and ClientComponent's and RepairComponent's input / output data is going to be a complex object, such as an interface:
interface ClientInputData {
    id: number;
    someInputData: any;
}

interface ClientOutputData {
    someOutputData: any;
}
  • Both AppComponent and RepairComponent should be able to communicate with their respective ClientComponent instance rendered within their MatDialog instance, using the same input / output interfaces used by AppComponent while communicating with the ClientComponent instance rendered into <router-outlet>;

  • At the same time, AppComponent should be able to distinguish whether it's getting data back from the ClientComponent instance rendered through the router or from the ClientComponent instance rendered within the MatDialog instance, because depending on the sender different actions would be taken.

As per the third requirement, it's not going to be easy or clean to use a singleton service at the AppComponent level to connect all the pieces (something like this):

@Injectable()
export class ComService {
    // code implementing an observable for each component's input and output
}

More specifically, it will be kind of cumbersome to keep track of whether AppComponent is receiving data from the ClientComponent instance rendered within <router-outlet>, the ClientComponent instance rendered within its child MatDialog or the ClientComponent instance rendered within RepairComponent's child MatDialog, which I don't even care about tracking;

Also, instantiating two different instances of the service at the AppComponent level, sendind them down the two different "paths" (the <router-outlet> "path" and the MatDialog "path") in order to solve the "tracking" problems wouldn't be possible either (as far as I'm aware of), as unless I'm missing something there would be no way to pass a single instance of the service down to the "path" of components rendered through <router-outlet> (researching on this has led me to understand that the only way to pass data down to components rendered within a <router-outlet> is through a service; but should I really create a service to share an instance of the actual service between the components in that "path"? Not to mention this would just slighlty change the issue and move it further in time to when multiple hierarcies of components or "paths" to keep track of will be implemented, because those "paths" will certainly need to be tracked as well).

Any ideas on how to solve this?

Aucun commentaire:

Enregistrer un commentaire