iT邦幫忙

2021 iThome 鐵人賽

DAY 10
1
Modern Web

Angular 常見問題大小事系列 第 10

Angular 下拉選單如何選定預設值

情境

當表單送出後,資料庫會記錄送出後的值,下次再進來時,會需要重現上一次所填寫過的內容,這在實作上是很常遇到的事情。

解決方式

原以為這是件很簡單的事,讀取資料後,直接把值填上後即可(想得太簡單了),
當實作時,卻怎麼樣也選不了預設值,後來發現在需要在 select 裡 加上 compareWith 比對,下拉選單才會正確選到所設定的預設值。


實作

這裡有套用到 Angular Material

以下是以複選值做範例

template

<mat-form-field>
  <mat-label>Label</mat-label>
  <mat-select multiple [formControl]="selected" [compareWith]="compareFn">
    <mat-option *ngFor="let option of options" [value]="option">
      {{ option.label }}
    </mat-option>
  </mat-select>
</mat-form-field>

component

interface option {
  label: string;
  value: string;
}

export class ExampleComponent implements OnInit {
  selected = new FormControl();

  options: option[] = [
    {
      label: "apple",
      value: "apple",
    },
    {
      label: "kiwi",
      value: "kiwi",
    },
    {
      label: "banana",
      value: "banana",
    },
    {
      label: "cherry",
      value: "cherry",
    },
  ];

  ngOnInit(): void {
    // 若 api 來的值是 fruits = ['banana', 'kiwi']
    // 先將值轉為 option 格式

    // 模擬api來的值
    of(["banana", "kiwi"])
      .pipe(
        take(1),
        map((fruits: string[]) => {
          return fruits.map((e) => {
            return {
              label: e,
              value: e,
            };
          });
        })
      )
      .subscribe((options: option[]) => {
        this.selected.setValue(options);
      });
  }
  compareFn(a: option, b: option): boolean {
    return a && b ? a.value === b.value : a === b;
  }
}

若是需要單選的話,將 html 裡的 multiple 移除

這裡需要注意的是,FormControl 裡的值,需與 options 裡選單的格式是一樣,值才會被正常選中


程式碼解說

這裡需要有 rxjs 的概念
範例使用 of 模擬 observable api 讀取進來的資料
rxjs operators 的 take 執行一次後
再使用 map 轉成我們需要的格式
接著再 subscribe (訂閱) 出來 將值塞到 FormControl 裡

範例:https://stackblitz.com/edit/angular-ivy-phixnz


參考資料:https://angular.tw/api/forms/SelectControlValueAccessor


上一篇
Angular 冒泡事件
下一篇
Angular 如何將多筆資料上傳後,取得全部回傳資料,再送到另一支 API
系列文
Angular 常見問題大小事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言