0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Ionic Framework / Capacitor / StencilAdvent Calendar 2022

Day 9

[Ionic Framework] ion-textareaとion-chipを使ってタグ入力UIを作る方法

Last updated at Posted at 2022-12-08

記事にタグを追加していくようなUI、結構どこでも見かけますよね。もちろんQiitaでも。

96dcdbe15248c9430aa41dd7b9ee3a59.gif

なのですが、あまりどう実装してるかを考えたことなかかったので、試しにプロダクトに実装してみたのでご紹介。

ちなみに着想はAngular MaterialのChips機能です。

a8c4a27fe982fdbc9567bab525acc148.gif

にデモがありますが、こういう便利なのを実装したいなと思ってコードをみたところ、Ionicでも比較的用意に実装できそうでした。Angular Materialでどう実装してるかを簡単にいうと、以下のどうなDOM構造になっています。

17ae3c487bf3300381b7d0e280dc381d.gif

Chipの横にInputがあり、入力されるとChipが増える。構造は簡単ですね。では、Ionicでこれを実装してみましょう。

<ion-list>
    <ion-item lines="full">
      <ion-label position="fixed">タグ</ion-label>
      <ion-text color="dark">{{ tags.length }}個登録中</ion-text>
    </ion-item>
    <ion-item color="light" class="tag-chips" lines="full">
      <div>
        <ion-chip outline="true" *ngFor="let item of tags">
          <ion-icon size="small" src="assets/icons/hashtag.svg"></ion-icon>
          <ion-label>{{ item.label }}</ion-label>
          <ion-icon name="close-circle-outline" (click)="removeTag(item)"></ion-icon>
        </ion-chip>
        <ion-textarea
          rows="1"
          placeholder="タグを入力"
          (ionChange)="detectInputTag($any($event))"
          #InputTag
        ></ion-textarea>
      </div>
    </ion-item>
</ion-list>
ion-item.tag-chips {
  --padding-start: 16px;
  div {
    padding: 8px 0;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;

    ion-textarea {
      margin: 0 0 0 8px;
      font-size: 1rem;
      flex-shrink: 0;
      min-width: 100px;
    }
  }
}

ion-chipion-textarea を配置する親要素を display:flex にして配置するだけです。簡単ですよね。 ion-input ではなく、 ion-textarea にしたのはエンターキーを押下したイベントを取得したかったからです。 ion-input ではできなかったのでこっちにしてるけど、ちょっとレイアウト狂うのでいつか再調査したいところ。

TypeScript側はこんな感じです。

@Component({
  selector: 'app-tags',
  templateUrl: './tags.component.html',
  styleUrls: ['./tags.component.scss'],
})
export class TagsComponent implements OnChanges {
  tags: ITag[] = [];
  @ViewChild('InputTag') inputTag: {
    el: IonInput;
  };
  constructor() {}

  ionViewDidEnter() {
    this.inputTag.el.setFocus().catch();
  }

  public detectInputTag(event: InputCustomEvent) {
    if (event.detail.value.length > 1 && event.detail.value.slice(-1).match(/( | |\r\n|\n|\r)/)) {
      this.tags.push({
        id: undefined,
        label: event.detail.value.trim(),
      });
      this.inputTag.el.value = '';
    }
  }

  public removeTag(tag: ITag) {
    this.tags = this.tags.filter((t) => {
      if (tag.id) {
        return t.id !== tag.id;
      }
      return t.label !== tag.label;
    });
  }
}

ポイントは、 ionChange で、空白もしくは改行が入力された時は detectInputTag メソッドが実行され、入力内容が tags プロパティにpushされたあと、入力内容が初期化されることぐらいですかね。あと使いやすさ的に入力欄に自動フォーカスさせるようにしていますが、これはUI設計にもよるのではないでしょうか。

ユーザにタグを入力してもらう時に活用してもらえればと思います。

それではまた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?