Continuing from this question Angular 4^ : How to have more than one child of a component with each child targeting its own router outlet, I'm able to have some child components injected into multiple parent components, now I want to pass data from those parents, async, to child. Tried @Input, can't seem to win.
Child
export class UserheaderComponent implements OnInit, AfterViewInit, OnChanges {
loading;
@Input() data;
user = {
name: '______________',
icon: '',
username: '_________',
uid: '________'
};
constructor(private router: Router) {
}
goToUser(uid) {
this.router.navigate(['user'], { queryParams: { uid: uid } });
}
ngOnInit() {
this.user = this.data;
console.log(this.data);
}
ngAfterViewInit() {
console.log(this.data);
}
ngOnChanges(changes: SimpleChanges) {
console.log(changes);
}
}
Parent Html
<router-outlet name='userprofile-userhead' [data]="currentUser"></router-outlet>
Parent TS
export class UserprofileComponent {
public currentUser;
constructor(
private userFactory: UserFactory,
private router: Router,
private snack: MatSnackBar) {
this.userFactory.checkSession(exists => {
if (!exists) {
return;
}
this.userFactory.getSessionUser((uid, user) => {
this.currentUser = user;
});
});
}
}
AND ROUTING
path: '', component: UserprofileComponent, outlet: 'userprofile', children: [
{ path: '', component: UserheaderComponent, outlet: 'userprofile-userhead' },
]
Nothing at all gets passed to child, is this possible with this kind of arrangement or I'm missing something?
Can't use a shared service.
Every component should use this with its own Id. Imagine this is in a timeline of posts like context, like a social media timeline, and this is a head of the post, you know, where the user icon, name...username is. So a 'post' component will inject this as a child, pass it a user object:{name:'...',username:'...'}
, so I don't see how a service will do here.
Now while we at that, somewhere on the app, a profile component, a search component might call this...
If you still think a service will do, please elaborate.
Using @Input() decorator We use the @Input() decorator to pass data from the parent to the child component via the template of the child component.
While there is no direct way to pass data from the child to the parent component, there are workarounds. The most common one is to pass a handler function from the parent to the child component that accepts an argument which is the data from the child component. This can be better illustrated with an example.
By adding the state isOpen to the parent, we can facilitate communication between the two sibling components. When the Button component is clicked it emits an event that updates the isOpen variable. That variable is then passed down to the Toggle component as a prop.
I get you, but I think shared service is still the answer of this question
You could try implementing a pub/sub service where you can assign which data will it subscribe and broadcast.
try this:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
/**
* Publisher/Subscriber Service
*/
@Injectable()
export class PubSubService {
private events: any = {};
constructor() { }
/**
* Subscribes the instance of the assigned event name
* @param eventName
* Event name of the delegate
*/
public On(eventName: PubSubEvents): Observable<any> {
if (typeof this.events[eventName] === 'undefined') {
this.events[eventName] = new Subject<any>();
}
return this.events[eventName].asObservable();
}
/**
* Broadcast data to the specified event channel
* @param eventName
* Event name of the delegate
* @param eventArgs
* Arguments to pass through to the connected channel
*/
public Broadcast(eventName: PubSubEvents, eventArgs: any) {
if (!this.events[eventName]) {
return;
}
this.events[eventName].next(eventArgs);
}
}
//Your events
export declare type PubSubEvents =
"OnChild1" | "OnChild2";
In parent component you have subscribe all of the events base on your needs.
Parent
constructor(private pubsub: PubSubService){
this.pubsub.On("OnChild1").subscribe((res) =>{ //Child 1 data}));
this.pubsub.On("OnChild2").subscribe((res) =>{ //Child 2 data}));
}
while in child component you have to do this
Child 1
constructor(private pubsub: PubSubService){
this.pubsub.Broadcast("OnChild1", "your_data")
}
Child 2
constructor(private pubsub: PubSubService){
this.pubsub.Broadcast("OnChild2", "your_data")
}
I think in this case one valid option is to add some parameter to the routing of your UserheaderComponent and then get it when the component is initing and get expected data from service.
First, you need to add it to route path of your component
path: 'userHead/:userId'
Then when you redirecting to that you need to set this parameter and then when the component is initializing you can get this
this.activatedRoute.params.subscribe((params) => { const userHead=
params['userId']; }
Finally based on that paremeter you can get expected data form service.
In the case when you will have a single child consider using component directly like that
<userprofile-userhead name='userprofile-userhead' [data]="currentUser">
</userprofile-userhead>
instead of the router-outlet.
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