Takumon/mean-blog

View on GitHub
src/app/articles/reply-form/reply-form.component.ts

Summary

Maintainability
F
5 days
Test Coverage
import {
  Component,
  OnInit,
  Input,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  AfterViewChecked,
} from '@angular/core';
import {
  FormGroup,
  FormControl,
  NgForm,
  Validators,
  FormBuilder,
} from '@angular/forms';
import { MatSnackBar } from '@angular/material';

import { Constant } from '../../shared/constant';
import {
  AuthenticationService,
  MessageService,
  MessageBarService,
} from '../../shared/services';
import { ReplyModel } from '../../shared/models';

import { ReplyService } from '../shared/reply.service';

/**
 * リプライ入力フォームのコンポーネント
 */
@Component({
  selector: 'app-reply-form',
  templateUrl: './reply-form.component.html',
  styleUrls: ['./reply-form.component.scss']
})
export class ReplyFormComponent implements OnInit, AfterViewChecked {
  /** 定数クラス、HTMLで使用するのでコンポーネントのメンバとしている */
  public Constant = Constant;

  /** コンポーネント初期表示時にリプライ入力エリアにフォーカスを当てるか */
  @Input() isAuthfocuse: boolean;

  /**
   * 処理対象のリプライモデル<br>
   * 更新時は既存のモデルを指定する<br>
   * 登録時は新規作成したモデルにarticleIdとuserを設定したものを指定する
   */
  @Input() model: ReplyModel;

  /** キャンセルボタンを表示するか */
  @Input() hasCancelBtn: boolean;

  /** 登録または更新完了時に発行するイベント */
  @Output() complete = new EventEmitter();

  /** キャンセル時に発行するイベント */
  @Output() cancel = new EventEmitter();

  /** フォーム */
  public form: FormGroup;

  /** 処理名(登録または更新) */
  public action: '登録' | '更新';

  /** コンストラクタ */
  constructor(
    private fb: FormBuilder,
    public snackBar: MatSnackBar,
    private ref: ChangeDetectorRef,

    public messageService: MessageService,
    private messageBarService: MessageBarService,
    private replyService: ReplyService,
    public auth: AuthenticationService,
  ) {
  }

  ngOnInit() {
    this.createForm();
    this.action = this.model.created ?  '更新' : '登録';
  }

  ngAfterViewChecked(): void {
    this.ref.detectChanges();
  }

  /**
   * Fromを作成し、値を初期化する
   */
  createForm() {
    this.form = this.fb.group({
      text: ['', [
        Validators.required,
        Validators.maxLength(400),
      ]],
    });

    this.form.patchValue({
      text: this.model.text
    });
  }

  /**
   * FromのtextのFromControlオブジェクトを取得する
   */
  get text(): FormControl { return this.form.get('text') as FormControl; }


  /**
   * 更新または登録処理をする<br>
   * <p>
   * 更新または登録後にフォームをクリアするが
   * FormGroupのresetではNgFormのsubmittedがクリアされないので
   * NgForm#resetFormを呼ぶ
   * </p>
   *
   * @param ngForm 更新または登録後にフォームを初期化するために引数にとる
   */
  upsert(ngForm: NgForm) {
    const form = this.form;
    if (!form.valid ) {
      return false;
    }

    this.model.text = form.value['text'];

    const action = this.isRegister()
      ? this.replyService.register(this.model)
      : this.replyService.update(this.model);

    action.subscribe(
      this.onSuccess.bind(this, ngForm),
      this.onValidationError.bind(this)
    );
  }

  /**
   * キャンセル時の処理
   */
  onCancel(): void {
    this.cancel.emit();
  }

  /**
   * actionが登録か
   *
   * @return 登録の場合true.更新の場合false
   */
  private isRegister(): boolean {
    return this.action === '登録';
  }

  /**
   * 登録または更新成功時の処理
   *
   * @param ngForm NgFormオブジェクト
   * @param res 登録または更新時のレスポンス
   */
  private onSuccess(ngForm: NgForm, res: any): void {
    this.snackBar.open(`リプライを${this.action}しました。`, null, this.Constant.SNACK_BAR_DEFAULT_OPTION);
    this.complete.emit();
    this.form.reset();
    ngForm.resetForm();
  }

  /**
   * 登録または更新失敗時の処理
   *
   * @param error エラー情報
   */
  private onValidationError(error: any): void {
    const noControlErrors = [];

    for (const e of error['errors']) {
      const control: FormControl | FormGroup = this[e.param];
      if (!control) {
        // 該当するfromがないものはスナックバーで表示
        noControlErrors.push(e);
        continue;
      }

      const messages = control.getError('remote');
      if (messages) {
        messages.push(e.msg);
      } else {
        control.setErrors({remote: [e.msg]});
      }
    }

    if (noControlErrors.length > 0) {
      this.messageBarService.showValidationError({errors: noControlErrors});
    }
  }
}