## 概要
[[Obsidianプラグイン]]の`Setting`では、以下のようにテキストエリアのコンポーネント追加コマンドがある。
```ts
new Setting(containerEl)
.setName("名前")
.addText((text) =>
text
.setValue(this.plugin.settings.name)
.onChange(async (value) => {
// 設定が変更されたときの処理
this.plugin.settings.name = value;
})
);
```
## 問題
上記コードの`onChange`は入力欄に変更があったとき、つまり1文字追加したり削除するごとにイベントが発生する。設定変更時にやや重めの処理を加えたい場合、連続してイベントが発生するので操作感を大きく損ねる。また、フォーカスが外れる処理をする場合は致命的になる。
一方、[[Obsidian API]]には`onChange`以外のIFが存在しない。
## 期待値
入力欄に変更があったときではなく、入力欄からフォーカスが外れたとき (変更後の入力内容が確定したとき) にイベントを実行したい。
## 解決方法
HTMLElementの`addEventListener`に直接セットする。
```ts
new Setting(containerEl)
.setName("名前")
.addText((text) => {
const el = text.setValue(this.plugin.settings.name);
el.inputEl.addEventListener("change", async (ev) => {
if (!(ev.target instanceof HTMLInputElement)) {
return;
}
// 設定が変更されたときの処理
this.plugin.settings.name = value;
});
return el;
});
```
## もっとオシャレに
[[メソッドチェーン]]できるようにラッパーを作るといい。
`settings-helper.ts`
```ts
import type { TextComponent } from "obsidian";
export namespace TextComponentEvent {
export function onChange(
component: TextComponent,
handler: (value: string) => void
): TextComponent {
component.inputEl.addEventListener("change", async (ev) => {
if (!(ev.target instanceof HTMLInputElement)) {
return;
}
handler(ev.target.value);
});
return component;
}
}
```
呼び出し側は以下のように書ける。
```ts
new Setting(containerEl).setName("名前").addText((text) =>
TextComponentEvent.onChange(text, async (value) => {
// 設定が変更されたときの処理
this.plugin.settings.name = value;
})
.setValue(this.plugin.settings.name)
);
```