问题
Using Angular 8 I have a few components as follows:
Parent 1 > Child 1 > ... > N Grandchild 1
Parent 2 > Child 2 > ... > N Grandchild 2
Between Child X and N Grandchild X might have other components. So it can be more than 3 levels.
Objective
1. Set a Value in N Grandchild 1 and use it in Parent 1.
2. Set a Value in N Grandchild 2 and use it in Parent 2.
I am considering a few options:
Using an EventEmitter (StackBlitz example)
Problem: Not working between Grandchild and Parent.
It seems to work only one level up ... It is possible to make it work N levels up?
export class GrandchildComponent implements OnInit { @Output() changeEvent = new EventEmitter<string>(); ngOnInit() { this.changeEvent.emit('Hello'); } }Using a Service
In this case I inject the Service in
N Grandchild Xto set the value and inParent Xto read the value.Problem:
How to be sure thatParent 1reads the value set byN GrandChild 1andParent 2reads the value set byN GrandChild 2? Is this possible?
回答1:
Like in another answer, which provides solution to use a Subject of some kind, but you face the issue that that subject and its value is shared across the app, if it's provided at root level.
One option is to provide the service at the parent level, which means that the parent and all its descendants have the same instance of the service, so therefore, if grandchild1 emits a value for the subject, only parent1 will receive that value, not parent2.
So what you would do, as mentioned, provide the service at the highest level you want, in this case I would assume it would be the parent:
import { MyService } from './my-service';
@Component({
selector: 'parent',
template: `
Parent:
<p>Value from grandchild: {{value$ | async}}</p>
<child></child>
`,
providers: [MyService] // <<<<<<<<<< add this (only in parent)!
})
export class ParentComponent {
value$;
constructor(private myService: MyService) {
this.value$ = this.myService.subj$;
}
}
and service could have:
private subj = new Subject();
public subj$ = this.subj.asObservable();
setValue(value) {
this.subj.next(value)
}
And in the grandchild when you want to emit value, just call setValue() with the new value.
STACKBLITZ
回答2:
First Way: You have to emit event on every level of chain, then only you will be able to get the event to the Parent component.
Parent 1(received) > Child 1(emit) > Child 2(emit) > N Grandchild 1(emit);
Second Way: Also for service you can create a message-bus kind of service, when you can specify from and to. So using those flag you can validate from where and for whom the data should be consumed by.
I personally think that you should go with the first approach.
回答3:
You could try using a BehaviorSubject in a injected service in both components, one component listening on the BehaviorSubject. And the other emiting new values for the subject.
@Injectable({
providedIn: 'root'
})
export class TestService {
subject: BehaviorSubject<any>;
constructor() {
this.subject = new BehaviorSubject(null);
}
getObservable() {
return this.subject.asObservable();
}
updateValue(value) {
this.subject.next(value);
}
}
来源:https://stackoverflow.com/questions/58975892/pass-value-between-grandchild-component-and-parent-component