简体   繁体   中英

Share a method between two child components (Angular)

There is such structure of components:

在此处输入图片说明

Desired Behavior

child1_component - is a header.

child2_component - is a body.

There is a button inside child1_component .

Clicking on that button I want to invoke a method inside child2_component .

Question

What is the best way to implement this?

One way to approach this would be to use a service with rxjs subjects and observables.

  1. When the user clicks on the button in child1_component then it calls a method that in turn calls a method inside the shared service.

  2. When the method in the service is called it can emit a value as an observable via a subject.

  3. child2_component then subscribes to the observable within the shared service and can operate some logic based on when it receives data from the service.

More on services here: https://angular.io/tutorial/toh-pt4

Great tutorial on subjects and rxjs: https://blog.angulartraining.com/rxjs-subjects-a-tutorial-4dcce0e9637f

There are 2 ways to do it:

1.Service:

    export class ActionService {
      private someAction = new Subject();


      someActionEmitted$(): Observable<unknown> {
        return this.someAction.asObservable();
      }

      emitSomeAction(): void {
        this.someAction.next();
      }
    }


    //childComponent1
    export class ChildComponent1 {
      constructor(private actionService: ActionService) {
      }

      emitAction(): void {
        this.actionService.emitSomeAction();
      }
    }

    //childComponent2
    export class ChildComponent2 implements OnInit, OnDestroy {
      private destroy$ = new Subject();

      constructor(private actionService: ActionService) {
      }

      ngOnInit(): void {
        this.actionService.someActionEmitted$()
          .pipe(takeUntil(this.destroy$))  // dont forget to unsubscribe, can cause memory leaks
          .subscribe(() => this.doSomething());
      }

      doSomething(): void {
        // your logic here
      }

      ngOnDestroy(): void {
        this.destroy$.next();
      }
    }

2. Using Parent Component

<child-component1 (btnClicked)="childComponentBtnClick()"></child-component1> <child-component2 [clickBtnSubject]="childBtnClicked"></child-component1>

Ts logic:

export class ParentComponent {
  childBtnClicked = new Subject();

  childComponentBtnClick(): void {
    this.childBtnClicked.next();
  }
}


//childComponent1
export class ChildComponent1 {
  @Output() btnClicked = new EventEmitter();


  emitAction(): void {
    this.btnClicked.emit(); // you can pass value to emit() method
  }
}

//childComponent2
export class ChildComponent2 implements OnInit, OnDestroy {
  @Input() clickBtnSubject: Subject;

  ngOnInit(): void {
    this.clickBtnSubject
      .pipe(takeUntil(this.destroy$))  // dont forget to unsubscribe, can cause memory leaks
      .subscribe(() => this.doSomething());
  }

  doSomething(): void {
    // your logic here
  }

  ngOnDestroy(): void {
    this.destroy$.next();
  }
}

On your general.component.html :

<app-child1 (clicked)="app1Clicked($event)"></app-child1>

<app-child2 #child2></app-child2>

On your general.component.ts:

@ViewChild('child2', {static: true}) child2: Child2Component;

app1Clicked($event) {
   this.child2.doSomething()
}

On the child1.components.ts:

@Output() clicked = new EventEmitter<any>();

onClick() {
 this.clicked.emit();
}

Finally on the child2.component.ts:

doSomething() {
 alert('ok');
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM