記事にタグを追加していくようなUI、結構どこでも見かけますよね。もちろんQiitaでも。
なのですが、あまりどう実装してるかを考えたことなかかったので、試しにプロダクトに実装してみたのでご紹介。
ちなみに着想はAngular MaterialのChips機能です。
にデモがありますが、こういう便利なのを実装したいなと思ってコードをみたところ、Ionicでも比較的用意に実装できそうでした。Angular Materialでどう実装してるかを簡単にいうと、以下のどうなDOM構造になっています。
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-chip
と ion-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設計にもよるのではないでしょうか。
ユーザにタグを入力してもらう時に活用してもらえればと思います。
それではまた。