首页 > 代码库 > [Angular] Component architecture and Reactive Forms

[Angular] Component architecture and Reactive Forms

It it recommeded that when deals with form component, we can create a container component to hold state, and then create a stateless component to enpower the form.

For example:

技术分享

In the example has two components, one is container component ‘meal.component.ts‘, another is statless component ‘meal-form.component.ts‘.

 

For the container component, it talks to service:

import {Component} from ‘@angular/core‘;import {Meal} from ‘../../../shared/services/meals/meals.service‘;@Component({  selector: ‘meal‘,  styleUrls: [‘meal.component.scss‘],  template: `    <div class="meal">      <div class="meal__title">        <h1>          <img src="/img/food.svg" alt="Food">          <span>Create meal</span>        </h1>      </div>      <div>        <meal-form          (create)="addMeal($event)"        ></meal-form>      </div>    </div>  `})export class MealComponent {  constructor() {  }  addMeal(meal: Meal) {    console.log("meal", JSON.stringify(meal, null, 2))  }}

So ‘addMeal‘ function will dispatch action to talk to the service.

 

For statless component:

import {ChangeDetectionStrategy, Component, EventEmitter, Output} from ‘@angular/core‘;import {FormBuilder, FormArray, FormGroup, FormControl, Validators} from ‘@angular/forms‘;import {Meal} from ‘../../../shared/services/meals/meals.service‘;@Component({  selector: ‘meal-form‘,  changeDetection: ChangeDetectionStrategy.OnPush,  styleUrls: [‘meal-form.component.scss‘],  template: `    <div class="meal-form">       <form [formGroup]="form">        <div class="meal-form__name">          <label>            <h3>Meal name</h3>            <input type="text"                    formControlName="name"                   placeholder="e.g. English Breakfast">            <div class="error" *ngIf="required">              Workout name is required            </div>          </label>        </div>                <div class="meal-form__food">          <div class="meal-form__subtitle">            <h3>Food</h3>            <button               type="button"               (click)="addIngredient()"              class="meal-form__add">              <img src="/img/add-white.svg" alt="Add food">              Add food            </button>          </div>          <div formArrayName="ingredients">            <label *ngFor="let c of ingredients.controls; index as i;">              <input type="text" [formControlName]="i" placeholder="e.g Eggs">              <span                class="meal-form__remove"                (click)="removeIngredient(i)"              ></span>            </label>          </div>        </div>                <div class="meal-form__submit">          <div>            <button type="button" class="button" (click)="createMeal()">              Create Meal            </button>            <a               [routerLink]="[‘../‘]"              class="button button--cancel">              Cancel            </a>          </div>        </div>      </form>    </div>  `})export class MealFormComponent {  @Output()  create = new EventEmitter<Meal>();  form = this.fb.group({    name: [‘‘, Validators.required],    ingredients: this.fb.array([‘‘])  });  get ingredients () {    // Type check for ingredients, mark as FormArray    // Therefore when we use ‘ingredients‘,    // We can get auto complete    return this.form.get(‘ingredients‘) as FormArray;  }  get required() {    return (      this.form.get(‘name‘).hasError(‘required‘) &&        this.form.get(‘name‘).touched    );  }  constructor(private fb: FormBuilder) {  }  createMeal() {    if (this.form.valid) {      this.create.emit(this.form.value);    }  }  addIngredient() {    // Add a new FormControl to FormArray    this.ingredients.push(new FormControl(‘‘));  }  removeIngredient(i: number) {    this.ingredients.removeAt(i);  }}

 

It uses ReactiveForm to create form.

 

Things to be notice:

1. Add type check for form array:

  get ingredients () {    // Type check for ingredients, mark as FormArray    // Therefore when we use ‘ingredients‘,    // We can get auto complete    return this.form.get(ingredients) as FormArray;  }

Then whenever you use ‘this.ingredients‘, it will show auto complete.

 

2. FormArray method:

  addIngredient() {    // Add a new FormControl to FormArray    this.ingredients.push(new FormControl(‘‘));  }  removeIngredient(i: number) {    this.ingredients.removeAt(i);  }

 

[Angular] Component architecture and Reactive Forms