Ionic 4 - Component within page/calling functions between them

Hello all!

I’m wondering what is the best solution to deal with this problem or if there is an alternative/best practise way to go about this.

I have a page which contains a custom component that is a simple input form (I want to use this form elsewhere as well, so it is a separate component). The page itself has a header with a back button and a save button for the form.

Example:

Page HTML

<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-button (click)="back()"
        ></ion-button>
    </ion-buttons>
    <ion-title>Page</ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="save()"
        ></ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content>
    <app-form></app-form>
</ion-content>

Form HTML

<form [formGroup]="form">
    <ion-input formControlName="name"></ion-input>
    <ion-input formControlName="age"></ion-input>
</form>

So I would want to save the values in the form component when the save button on the page is clicked. I have tried the following solution:

In form component .ts

  compileInput() {
    let person = {
      name: this.form.controls.name.value,
      age: this.form.controls.age.value,
    };
    console.log(person);  /// <--- this prints person with blank values?
    return person;
  }

And in my page .ts

 constructor(
    private router: Router,
    private service: Service,
    private form: FormComponent
  ) {}

  ngOnInit() {}

  public home() {
    this.router.navigateByUrl("home");
  }

  public save() {
    this.service.save(this.form.compileInput());
    this.home();
  }

What is a good way to deal with this?

Thankyou in advance :slight_smile:

using [ngModel] in ion-input would be great

compileInput could be simplified greatly, because forms also have a value. If form.value isn’t what you want there, I would redesign FormComponent so that it is.

As for the more major issue, DI is for services, not for components. Attempting to inject FormComponent into a page makes no sense. I can think of two options: one relatively easy and one harder but IMHO more accurately expressing what FormComponent is really trying to do.

The easy way is @ViewChild. The harder way is to make FormComponent act like a single control itself, so that it can be incorporated in higher-order forms and work on a Person. Here is an article describing the tactic.

There are a few ways to get this done. I’ll show a pretty easy one that can used to access any type of child component from a parent component using @ViewChild.

Make sure to import ReactiveFormsModule

page.ts

@ViewChild('directiveNameToPlaceOnComponent', { static: false }) someFormComponent: any;

  public save() {
    console.log(this.someFormComponent.form.value);
  }

page.html

<ion-header>
  <ion-toolbar>
    <ion-title>Page</ion-title>
    <ion-buttons slot="end">
      <ion-button (click)="save()"
        >Save</ion-button>
    </ion-buttons>
  </ion-toolbar>
</ion-header>

<ion-content>
    <app-form #directiveNameToPlaceOnComponent></app-form>
</ion-content>

form.component.ts

constructor(private readonly formBuilder: FormBuilder) { }

  public form = this.formBuilder.group({
    name: [undefined],
    age: [undefined]
  })

form.component.html
Form:

<form [formGroup]="form">
  <ion-input formControlName="name"></ion-input>
  <ion-input formControlName="age"></ion-input>
</form>

The output of the save button:
{name: “John Doe”, age: “76”}