iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0

昨天調整mock-data有調整到檢核的部分
不過檢核的部分寫在Form-input好像也會讓這邊太複雜
而且為了方便日後管理與擴增
我們今天會多拆一個validator.service

import { Injectable } from '@angular/core';
import { ValidatorFn, Validators } from '@angular/forms';

@Injectable({
    providedIn: 'root'
})
export class ValidatorService
{

    constructor() { }

    getValidators(validatorStrings: string[]): ValidatorFn[]
    {
        return validatorStrings.map((v: string) =>
        {
            let keyword = v.split(':')
            switch (keyword[0])
            {
                case 'required':
                    return Validators.required;
                case 'maxLength':
                    return Validators.maxLength(Number(keyword[1]));
                default:
                    return null;
            }
        }
        ).filter(v => !!v) as ValidatorFn[]
    }
}

我們把原本form-input的邏輯搬進來
這邊我們的概念是傳原本的字串陣列近來
然後傳ValidatorFn陣列出去
這個型別可以直接丟到addValidator裡面

// form-input.component.ts
if (setting.validator && setting.validator?.length > 0)
{
    if (!!setting.validator.find(v => v == 'required')) setting.required = true;
    newControl.addValidators(this.validatorService.getValidators(setting.validator))
}

然後這邊的話原本會另外設定required這個值
這邊在設定檔裡面就修改成不額外設定
如果validator裡面有required的時候就把fieldSetting裡面的required設為true

另外 我們也可能會有一些自定義的檢核的部分
也是可以寫在validator.service裡面
這邊想寫一個有點特別的自定義檢核
就是radioText元件裡面的
如果radio勾選true則text必填
這邊的邏輯我設計成
若這個欄位的parent之下的某個欄位為true則必填
這個某個欄位我可以從外面傳入
這樣關鍵字可以設定成像這樣

{
  "name": "radioTextRadio1",
  "cname": "控制輸入欄位",
  "inputType": "radio",
  "defaultValue": "true",
  "groupName": "radioText1",
  "groupType": "radioText-radio",
  "options": [
    { "label": "是", "value": "true" },
    { "label": "否", "value": "false" }
  ]
},
{
  "name": "radioTextText1",
  "cname": "控制輸入欄位",
  "inputType": "text",
  "groupName": "radioText1",
  "groupType": "radioText-text",
  "placeholder": "勾選後才可輸入",
  "defaultValue": "",
  "validator": ["requiredTrueWithField:radioTextRadio1"] //新增特殊關鍵字
},

這樣validator.service裡面會長像這樣

    getValidators(validatorStrings: string[]): ValidatorFn[]
    {
        return validatorStrings.map((v: string) =>
        {
            let keyword = v.split(':')
            switch (keyword[0])
            {
                case 'required':
                    return Validators.required;
                case 'maxLength':
                    return Validators.maxLength(Number(keyword[1]));
                case 'requiredTrueWithField':
                    return this.requiredTrueWithField(keyword[1]);
                default:
                    return null;
            }
        }
        ).filter(v => !!v) as ValidatorFn[]
    }

    requiredTrueWithField(fieldName: string): ValidatorFn
    {
        return (control: AbstractControl): { [key: string]: any } | null =>
        {
            if (!control.parent)
            {
                return null;  // 如果 control 沒有 parent,則返回 null(暫時不驗證)
            }

            const fieldControl = control.parent.get(fieldName);
            fieldControl?.valueChanges.pipe(distinctUntilChanged()).subscribe(r =>
            {
                control.updateValueAndValidity();
            })
            if (fieldControl && fieldControl.value == "true")
            {
                // 如果 A 為 true,B 必填
                return Validators.required(control) ? { required: true } : null;
            }

            return null;  // A 不是 true,B 無需必填
        };
    }

由於這個檢核是寫在text上
但我們需要radio異動的時候也要刷新狀態
所以我們要在這裡面對radio做監聽並處理
如果有其他想要新增的檢核 就可以通通在Validator.service裡面做處理

今日程式:day23


上一篇
第22天 mock-data
下一篇
第24天 特殊元件 列表
系列文
簡單的事 最困難-Angular動態Form元件30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言