Pass value between Grandchild component and Parent component

|▌冷眼眸甩不掉的悲伤 提交于 2020-02-27 13:52:23

问题


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:

  1. 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');
      }
    
    } 
    
  2. Using a Service

    In this case I inject the Service in N Grandchild X to set the value and in Parent X to read the value.

    Problem:
    How to be sure that Parent 1 reads the value set by N GrandChild 1 and Parent 2 reads the value set by N 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!