How to observe the execution of methods in parent components in child components

Posted by GundamSV7 on Fri, 04 Mar 2022 07:14:23 +0100

We may encounter the following situations:
At present, we need to write an auto complete component. When the content entered by the user is recorded in the database, it will be saved according to the record. If there is no record, the content entered by the user will be stored in the database as an entity before saving. But we certainly can't store as long as the content entered by the user is not found in the database. If so, as long as the user changes the content in the input box once, it will be stored once. Obviously, this is unreasonable.
So what we need to do is to do the above operation after the user has confirmed that he has entered all the contents and clicked save.
Then the question arises - how to know that the parent component has clicked the Save button in the child component?

Previously on:
We specify that when you click the Save button, the onSubmit method of layer C will be executed to submit the form.

<form [formGroup]="formGroup" (ngSubmit)="onSubmit(formGroup)">
<app-vehicle-brand-auto-complete [formControlName]="formKeys.vehicleBrand" ></app-vehicle-brand-auto-complete> //This is the subcomponent we want to call
  <div>
    <div>
      <button [disabled]="formGroup.invalid" type="submit">preservation
      </button>
    </div>
  </div>
</form>

So what we need to do is to know the execution of onSubmit method in the parent component in the child component.
At first, I wondered whether angular has built-in this method. We only need to pass the onSubmit of the parent component to know its call time, but no similar method was found after testing.

To know the execution, we first declare a variable of type observable with the @ Input annotation in the sub component.

  @Input()
  doSubmit: Observable<void>

Then we declare this in the parent component

  /**
   * It is used to snap the value to the sub assembly and make the sub assembly determine the reliability
   */
  doSubmitSubject = new Subject<void>();
  /**
   * It is used to pass to the sub component and make the sub component subscribe
   */
  doSubmit = this.doSubmitSubject.asObservable();

At this time, doSubmitSubject has the function of ejecting information from the component. doSubmit is used to pass it to the sub component for subscription.
If we want to implement the corresponding method of subcomponents when the user clicks save, we only need to call doSubmitSubject. in the onSubmit method. Pass the value to next().

onSubmit(formGroup: FormGroup) {
  this.doSubmitSubject.next(null);
  . . .
}

Then we can subscribe to the doSubmit in the sub component

ngOnInit(): void {
  this.doSubmit.subscribe(
  //What we want to do
  )
  . . .
}

After knowing the method, we also need to know what Subject is and why it can realize the above functions.

export class Subject<T> extends Observable<T> implements SubscriptionLike {
. . .

}

After looking at its code, we find that Subject inherits from Observable.
Let's look at the asObservable method:

  asObservable(): Observable<T> {
    const observable = new Observable<T>();
    (<any>observable).source = this;
    return observable;
  }

The official notes are as follows:

Create a new observable object from this host.
You can do this to create custom observer side logic for objects and hide it from code that uses observable objects.
Return value:
Observable from Subject Projected Observable

The observer logic can be called, that is, the observer logic Next () is equivalent to passing values to Observable in our daily use, so as to trigger the subscription of sub components and carry out corresponding operations.

However, after the above operations, we will find that because the operations are asynchronous, the parent component will complete the save operation before the child component, that is to say, the parent component has completed the save operation before the corresponding functions of our child component have been executed and the complete entity has not been passed to the parent component.
At this time, we need to add a befiniishi field with the @ OutPut field to tell the parent component that we have finished execution, and the parent component will store it after receiving the message.
Sub components:

  @Output()
  beFinish = new EventEmitter<void>();
  ngOnInit(): void {
    this.doSubmit.subscribe(() => {
      xxxService
        .subscribe(() => {
          . . .
          this.beFinish.emit(null);
          })
    })

Parent component (layer C):

finish = false;

onFinish(formGroup: FormGroup) {
    this.finish = true;
    this.onSubmit(formGroup);
  }

  onSubmit(formGroup: FormGroup) {
    //If = > is not completed, it indicates that all fields have been entered and onSubmit method has been executed
    //If completed, call M layer for corresponding operation
    if(this.finish === false) {
      this.doSubmitSubject.next(null);
    } else {
      const newVehicleBrand = new VehicleBrand({
        id: formGroup.get(this.formKeys.vehicleBrand).value.id as number,
        name: formGroup.get(this.formKeys.vehicleBrand).value.name as string
      });
      //Invoke the corresponding service in if statement to store operation.
      console.log(newVehicleBrand);
    }
  }

Parent component V layer

<app-vehicle-brand-auto-complete [formControlName]="formKeys.vehicleBrand" [doSubmit]="doSubmit" (beFinish)="onFinish(formGroup)"></app-vehicle-brand-auto-complete>

This concludes the whole process. For ease of understanding, the following flow chart is provided:

Many times, it is necessary to draw a flow chart with correct logic first, which can well prevent the code we write from entering the dead loop.

Topics: angular TypeScript