iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0

昨天我們增加了一個地址的檔案怪物
如果這些放在元件裡面 會很恐怖的吧
剛好之前其實就有想把main的設定檔抽取出來
這樣我們來做個mock-data吧

首先即使我們要做mock-data
也是要模擬打api的行為
這樣我們做個data.service在share/service之下

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class DataService
{
    private jsonUrl = 'assets/mock/main-data.json';

    constructor(private http: HttpClient) { }

    getMainData(): Observable<any>
    {
         return this.http.get(this.jsonUrl);
    }
}

然後把原本main的設定檔搬到assets/mock/main-data.json之下

{
  "pageSettings": [
    {
      "title": "第一頁",
      "fieldSettings": [
        {
          "name": "addressCity",
          "cname": "地址",
          "inputType": "select",
          "groupName": "address1",
          "groupType": "address-city",
          "options": []
        },
 ...以下省略

原本main的地方改成在ngInit的時候讀取

    pageSettings!: PageSetting[]

    constructor(private dataService: DataService) { }

    ngOnInit(): void
    {
        this.dataService.getMainData().subscribe(data =>
        {
            this.pageSettings = data.pageSettings;
        })
    }

不過這樣調整會有問題
原本validator的陣列我們是直接使用原生的Validator
改成json後會失效
這樣我們調整成用"required" "maxLength:3"這樣的關鍵字去紀錄
在讀取設定檔轉換成form的時候再調整

//form-input.component.ts
    let newControl = this.fb.control(setting.defaultValue) as FormControl;
    if (setting.validator && setting.validator?.length > 0)
    {
        setting.validator?.forEach((v: string) =>
        {
            let keyword = v.split(':')
            switch (keyword[0])
            {
                case 'required':
                    setting.required = true;
                    newControl.addValidators(Validators.required);
                    break;
                case 'maxLength':
                    newControl.addValidators(Validators.maxLength(Number(keyword[1])));
                    break;
            }
        })
    }

原本let newControl會直接使用setting.validator
這邊變成下面跑回圈去addValidators

然後剛剛API的部分畢竟是模擬
考慮到日後可能會真的接API
我們把mock的部分轉移到intercept裡面
創建mock.interceptor

import { Injectable } from '@angular/core';
import
{
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';

@Injectable()
export class MockInterceptor implements HttpInterceptor
{


    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
    {
        // 判斷是否啟用 mock
        if (environment.isMock)
        {
            // 如果是 mock,將請求重定向到本地 JSON 文件
            const mockReq = req.clone({
                url: `assets/mock/${req.url}-data.json`  // 假設所有本地 JSON 文件存放在 assets/mocks 中
            });
            return next.handle(mockReq);
        } else
        {
            // 否則繼續使用原本的 URL
            return next.handle(req);
        }
    }
}

這邊攔截Http 如果isMock 那就指向到本地文件
這邊有調整到環境變數

//environment.ts
export const environment = {
    production: false,
    isMock: true //增加這個
};

data.service會調整一下 再加上地址的部分會是這樣

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class DataService
{
    // private jsonUrl = 'assets/mock/main-data.json';

    constructor(private http: HttpClient) { }

    getMainData(): Observable<any>
    {
        // return this.http.get(this.jsonUrl);
        return this.http.get('main');
    }

    getAddressData(): Observable<any>
    {
        // return this.http.get(this.jsonUrl);
        return this.http.get('address');
    }
}

這樣調整就方便日後擴充
也方便開關 很棒吧

今日程式:day22


上一篇
第21天 地址元件
下一篇
第23天 檢核管理
系列文
簡單的事 最困難-Angular動態Form元件30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言