vue-tags-inputをインストールする
- @frk/vue-tags-inputをインストール
// npmの場合
npm install --save @frk/vue-tags-input
// yarnの場合
yarn add @frk/vue-tags-input
Vueコンポーネントで使ってみる
今回はLaravelのコンポーネントとして使うので、下記条件を満たすよう実装する
- どのフォームからも使用できるように、name属性をpropで指定できるようにする
- 編集画面などでも使えるように、デフォルト表示のタグたちを指定できるようにする
- submit時にPOSTするための値をhiddenで保持するようにする
ソースはこんな感じ
- TagInput.vue
<template>
<div>
<vue-tags-input
v-model="inputTag"
:tags="selectedTags"
@tags-changed="newTags => selectedTags = newTags"
:autocomplete-items="filteredItems"
@before-adding-tag="checkValidTag"
:existing-tags="existingTags"
:name="name"
placeholder="タグを追加"
/>
<input type="hidden" :name="name" :value="tagsValue" />
<div v-if="errorText" class="error-text">{{ errorText }}</div>
</div>
</template>
<script>
import VueTagsInput from '@frk/vue-tags-input';
export default {
components: {
VueTagsInput,
},
props: {
// 既存のタグたち
existingTags: {
type: Array,
default: () => []
},
// タグの初期値
defaultTags: {
type: Array,
default: () => []
},
// inputのname属性
name: {
type: String,
default: null
},
},
data() {
return {
// 入力中のタグ文字列
inputTag: '',
// 選択されたタグ
selectedTags: [],
// エラー文言
errorText: '',
};
},
created() {
// 初期表示したいタグがあれば代入する
this.selectedTags = this.defaultTags
},
computed: {
/**
* autoCompleteのフィルタリング
* @returns {*[]}
*/
filteredItems() {
return this.existingTags.filter(tag => {
return tag.text.toLowerCase().indexOf(this.inputTag.toLowerCase()) !== -1;
});
},
/**
* hidden属性に持たせるvalueを生成する
* @return string
*/
tagsValue() {
return this.selectedTags.map(function (tag) {
return tag['text'];
}).join(',')
},
},
methods:{
/**
* タグの形式をチェックする
* @param obj
*/
checkValidTag(obj) {
if (obj.tag.text.length > 30) {
this.errorText = 'タグは30文字以内で入力してください'
} else {
this.errorText = ''
obj.addTag();
}
},
},
};
</script>
- Laravelのview側ではこんな感じで呼び出す
<tag-input
:existing-tags="[{text: 'Cat'}, {text: 'Dog'}, {text: 'Rabbit'}]"
:default-tags="[{text: 'Cat'}]"
name="tags"
></tag-input>
使ってみるとこんな感じ
textをkeyにしたオブジェクト配列を渡しているのは、後述の自動補完関連の兼ね合い。
もしModelの値とかを渡してあげたいときはゲッターで整形してあげればいいと思う
propのexisting-tags
(=既存のタグ一覧)やdefault-tags
(=デフォルト表示にしたいタグ) は
指定がない場合は何も渡さなければOK
バリデーションエラー時にold値をデフォルトで渡してあげたい場合
若干力技で書くとこんな感じ
@php
$defaultTags = [];
if (old('tags')) {
foreach (explode(',', old('tags')) as $tag) {
$defaultTags[] = ['text' => $tag];
}
}
@endphp
<tag-input
:existing-tags="[{text: 'Cat'}, {text: 'Dog'}, {text: 'Rabbit'}]"
:default-tags="{{ json_encode($defaultTags) }}"
name="tags"
></tag-input>
ざっくり補足
丁寧かつ詳しいドキュメントはこちら
propで受け取っているもの
existingTags
: 既存のタグ一覧を入れた配列
文字を入力した際に、この配列の中に文字一致するものがあれば自動補完される仕組みdefaultTags
: デフォルト表示しておきたいタグ一覧を入れた配列
編集時などに指定するname
: hiddenで生成するPOST用データのname属性
dataで定義しているもの
inputTag
: v-modelに指定しているので、入力中のタグ文字列はここに入るselectedTags
: @tag-changedイベントで指定しているので選択されたタグ一覧がここに入るerrorText
: 文字数オーバーの時にエラー文言を入れる
自動補完リストはcomputed
で生成しているfilterdItems
の値
/**
* autoCompleteのフィルタリング
* @returns {*[]}
*/
filteredItems() {
return this.existingTags.filter(tag => {
return tag.text.toLowerCase().indexOf(this.inputTag.toLowerCase()) !== -1;
});
},
ここではthis.existingTags
(=既存のタグ一覧) の中にthis.inputTag
(=入力中の文字列) が含まれていれば、
それをフィルタリングして返している
その値を:autocomplete-items
に渡してあげれば
自動補完として表示してくれるっていう流れ
※ :autocomplete-items
に渡す値は、
必ず下記のようなtextをkeyに指定したオブジェクト配列で渡す必要がある[{text: 'Cat'}, {text: 'Dog'}, {text: 'Rabbit'}]
ここでhidden属性を埋め込んでる
<input type="hidden" :name="name" :value="tagsValue" />
これが実際Controller側に渡される値になる
name属性はpropで受け取ったname
を指定して、
value属性にはcomputedで定義したtagsValue
を入れてる
/**
* hidden属性に持たせるvalueを生成する
* @return string
*/
tagsValue() {
return this.selectedTags.map(function (tag) {
return tag['text'];
}).join(',')
},
ここではthis.selectedTags
(=選択されているタグ一覧) の
text部分をカンマ区切りの文字列に変換している
実際のタグ表示はこんな感じ
<input type="hidden" name="tags" value="Cat,Dog">
ちなみにタグ選択時に自動で更新されるthis.selectedTags
の値をデバッグしてみると
[ { "text": "Cat", "tiClasses": [ "ti-valid" ] }, { "text": "Dog", "tiClasses": [ "ti-valid" ] } ]
この形式は変更できないので、上記のようにcomputedで文字列に組み立て直してる
30文字以上の入力は弾くバリデーションチェックをcheckValidTag()
メソッドで行っている
checkValidTag(obj) {
if (obj.tag.text.length > 30) {
this.errorText = 'タグは30文字以内で入力してください'
} else {
this.errorText = ''
obj.addTag()
}
},
これの呼び出し元である@before-adding-tag
はその名の通り、
タグが追加される直前に呼び出されるイベント
ここで、文字列の長さをチェックして、NGならエラー表示 / OKならobj.addTag()
でタグ追加を行っている
(ここから余談)
実はvue-tags-inputには、validation
というのが指定できて、下記のようなpropを渡すことでチェックをすることもできる
<template>
<vue-tags-input
// (...諸々省略)
:validation="validation" // ⭐️ここ
/>
</template>
<script>
import VueTagsInput from '@frk/vue-tags-input';
export default {
// (...諸々省略)
data() {
return {
// (...諸々省略)
// ⭐️ここ
validation: [{
classes: 'max-length',
rule: tag => tag.text.length > 30,
}],
};
},
}
</script>
しかしこれはあくまで「タグの色」を変えるもので、実際の入力は弾いてくれない
(disableAdd
を指定すると弾いてはくれるみたいだけど・・)
http://www.vue-tags-input.com/#/examples/validation
なので今回は使用してない
タグ確定時のキーを追加したい
デフォルトではエンターキー (13) を押すとタグが追加される
例えばここにスペースキー(32) やキー文字列 (,) を指定したい時
- add-on-keyをpropで渡す
<vue-tags-input
...省略
:add-on-key="[13, 32, ',']"
/>
Laravelのviewで使用できる、タグ入力コンポーネントを実装した
コピペで使用できる、たぶん