How to implement nested secondary routing and still get the data from child? Angular 6

Issue

My goal is to send data from a routed child to the parent. I want to get the reference of a variable from the child, which is nested within a child to the parent through secondary routes so that the variable is synced to the parent. This variable will eventually be the boolean of a form validation state. Unfortunately, when I use Behavior Subject I think I have to use the component selector which seems not to play nicely with the routes in my application.

This is a sample from the template of the application…
It seems when I add the app-new-user component selector it screws up the newuserinput named router outlet 🙁

<!-- To BLADE LAYER 3 -->
<router-outlet></router-outlet>
<!-- <router-outlet name="newuserinput" (newUserInfoCompleteEvent)="receiveNewUserInfoComplete($event)"></router-outlet> -->
<router-outlet (activate)='getVState($event); ' name="newuserinput"></router-outlet>
<router-outlet name="newuserorginfo"></router-outlet>
<router-outlet name="newusersupervisorinfo"></router-outlet>
<router-outlet name="newusersecurityinfo"></router-outlet>
<!-- end -->



<!-- For ViewChild: bringing form validity state from child -->
<!-- <app-new-user-input style="display:none;"></app-new-user-input> -->
<!-- can't do this because putting the child component selector in the parent disables the childs router outlet -->

In mystackblitz prototype that I have prepared, the child/parent structure is successfully working with the service to display the desired information; however, as soon as I replace the component selectors in the parent(app-component) with named routes (like in the snippet of my application that I provided above) this breaks. My goal for this prototype is to display ‘Hello from secondary child’ on the parent with the secondary routing route params being properly displayed in the address bar like this:
https://behavior-subject-0007.stackblitz.io/(child:child/(secondarychild:secondarychild))

My question: So, how do I implement nested secondary routing and still get the data by reference from child to parent so that the address bar displays like this https://behavior-subject-0007.stackblitz.io/(child:child/(secondarychild:secondarychild))?

Can I use Behavior Subject for this or is there a better way? I was thinking about trying to implement AJ2_82’s solution.

I was also looking into simple property binding on the routed child component by using the components host metadata…

I’m relatively new to programming so there could be an ‘obvious’ solution, thanks for any help you can provide.

If you share YOUR way that would satisfy the same requirements (named router outlet address and data by reference from child to parent) I am all ears. Thank you.

Solution

One from many outlets to the problem is to use events , load an event emitter to your shared service public onChange: EventEmitter<string> = new EventEmitter<string>(); then brodcast it from the parent to its children, or counterwise, like this

changeMessage(message: string) {
    this.currentMessage = of(message)
    this.onChange.emit(message); 
  }

In each occurence when a desired component you want it to join the communicative hive, add an event catcher from this service: this.myService.onChange.subscribe(message=> this.message = message);

This way you could implement an “outward” but complete functional approach to share data at real time between routes.

see this sample.
Or you can see this slightly different implementation that merges sibling components and routes.


Or you can use idiosyncratic route parameters

By this way you wouldn’t allow any foreign component from another coexistant hierarchy to interfer in these inner messages exchanged between a defined module of routes, because you are underhandedly passing them inbetween.

You would configure the module this way:

export const routes: Routes = [
  { path: '', redirectTo: 'component-one/:message', pathMatch: 'full' },
  { path: 'component-one/:message', component: ComponentOne },
  { path: 'component-two/:message', component: ComponentTwo,
    children: [
      { path: '', redirectTo: 'child-one', pathMatch: 'full' },
      { path: 'child-one/:message', component: ChildOne },
      { path: 'child-two/:message', component: ChildTwo }
    ]
  }
];

So that each call to one of those filiations accompanies some parameter to be used in the component html core of which.

In the following example, I made the parameter in function call optional to tell if it was triggered from a component load, thus regenerated, neverthless it originates from a button click, hence just updated respectively to some custom parts.

newMessage(param?) {

    if(typeof(param) === 'undefined')
       this.message = "Parent";
    else
       this.message = param;

    var actualroute=this.router.routerState.snapshot._root.children[0].children[0].value.url[0].path;
    this.router.navigate(['/component-two', this.message , actualroute, this.message  ],{relativeTo: this.route});   
}

You can see it all working here. Thank you for this fun-challenge.

Weak spot: At each update of the variable message, the router proceeds to navigate all over again to the same hierarchy which costs time especially for bigger implementations.

Strong point: When you call a router.navigate there is ability to pass custom data between components, say ‘mesage1’ for a child and ‘message2’ for a parent in one row: this.router.navigate(['/component-two', 'message2' , 'child-one', 'message1']);. This can be done but very complicatedly and condition-entangledly using a service.

Answered By – Abr001am

Answer Checked By – Clifford M. (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.