2

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.

imnickvaughn
  • 2,774
  • 9
  • 25
  • 42
  • 1
    You may add some code to the body of question to not look more narrative than technical. – Abr001am May 29 '18 at 13:28
  • will do, thanks for the suggestion – imnickvaughn May 29 '18 at 13:39
  • 1
    i implemented an intercommunicative service with event emitter [here in this sample](https://stackblitz.com/edit/angular-lecmos?file=src%2Fapp%2Fmyservice.ts) , where you see that two child nested roots update the status of their routing parent accordingly when called, if this responds to your needs, let me know so i will formulate an answer. – Abr001am May 29 '18 at 19:19
  • okay i will look at it now, thank you – imnickvaughn May 29 '18 at 19:28
  • I believe that would solve my problem. At the moment, trying to see if I can use named router outlets and get the sibling message to work in your example. Thankk you! – imnickvaughn May 29 '18 at 19:43
  • 1
    ok then, i will try to adapt my template to yours keeping sain the substantial event-broadcasting between routes, an answer will follow within the range of 30 m. – Abr001am May 29 '18 at 20:06
  • imnickvaughn , wait, i just figured another implementation, stay up to changes. – Abr001am May 29 '18 at 21:50

1 Answers1

3

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.

Abr001am
  • 571
  • 6
  • 19
  • Brilliant, I only wish I could better understand what you are saying. For example, I could not find what you meant by idiosyncratic route parameters. Anyway, thank you! – imnickvaughn May 30 '18 at 18:51
  • @imnickvaughn they are parameters passed implicitly between routes, you can customize them at each navigation – Abr001am May 31 '18 at 02:17
  • ahh, dynamic route parameters, okay. Thanks – imnickvaughn May 31 '18 at 14:33
  • @imnickvaughn you tell that something is idiosyncratic if it doesn't leave the (sender/recipient) circle, and when it is translated/dispatched within this circle. – Abr001am Jun 01 '18 at 06:34