Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vahidhedayati/3f27db7fb8a12f24a8a5102bae69bc06 to your computer and use it in GitHub Desktop.
Save vahidhedayati/3f27db7fb8a12f24a8a5102bae69bc06 to your computer and use it in GitHub Desktop.
vue-tagsinput-example

I have added 2 new fields remoteKey remoteValue to the VoerroTagsInput.vue which is referred to by other local vue These are the definitions of what comes back from the db - so a db could have city object stored and it could come back as cityId and cityName as the two fields we are searching for from a given dynamic data set -

In this gist I have included 2 other files:

  1. a wrapper class for VoerroTagsInput.vue which is referred to by other local vue
  2. The actual example vue calling and rewriting db data to match above sample and VoerroTagsInput.vue appears to locally work fine

Assuming we have remote values of

cities:[
  {cityId:'1',cityName:'London' cityDescription:'We don't care not going to be used'},
  {cityId:'2',cityName:'Manchester' cityDescription:'We don't care not going to be used'},
]

Or

countries:[
  {countryId:'1',countryName:'London' countryDescription:'We don't care not going to be used'},
  {countryId:'2',countryName:'Manchester' countryDescription:'We don't care not going to be used'},
]

We would set our remoteKey='countryId' and remoteValue='countryName'

So this now tells vue-tagsinput to collect from remote object above key value for city object we would simply change to match what we wanted to collect.

The existing keyField valueField are used to build the actual produced tags within the users input box.

so if user wishes to collect cityId as id
[{"id":"aa","name":"bb"},{"id":"ab","name":"cc"},{"id":"some_id","name":"London"}]

Now if we declared the sample page like this:

 key-field="myOddCityId"
                      value-field="myOddCityName"

                      remote-key="cityId"
                      remote-value="cityName"
                      
                   and under created where commented if  we had:
       created() {
            this.selectedTags =  [{myOddCityId:'aa', myOddCityName:'bb'},{myOddCityId:'ab', myOddCityName:'cc'},]
        },
    We end up with (after I select a new one like this) within the input area
        value="[{"myOddCityId":"aa","myOddCityName":"bb"},{"myOddCityId":"ab","myOddCityName":"cc"},{"myOddCityId":"new cityid","myOddCityName":"East London"}]"
<template>
<div
class="vue-tags-input"
:class="[{ 'disabled': disabled }]"
>
<tags-input element-id="tags"
:existing-tags="existingTags"
:limit="limit"
:before-adding-tag="tag => disabled?false:true"
:before-removing-tag="tag => disabled?false:true"
:only-existing-tags="true"
:key-field="keyField"
:value-field="valueField"
:remote-value="remoteValue"
:remote-key="remoteKey"
:case-sensitive-tags="false"
:disabled="disabled"
typeahead-style="dropdown"
:typeahead="true"
@change="updateItems"
@initialized="onInitialized"
@tag-added="onTagAdded"
@tag-removed="onTagRemoved"
@tags-updated="onTagsUpdated"
@keydown="onKeyDown"
@keyup="onKeyUp"
@focus="onFocus"
@blur="onBlur"
wrapper-class="form-control"
v-model="currentTags"
></tags-input>
</div>
</template>
<script>
//import VoerroTagsInput from './VoerroTagsInput';
import VoerroTagsInput from '@voerro/vue-tagsinput';
export default {
name: 'my-tags-input',
inject: ["$validator"],
props: {
keyField: {
type: String,
default: 'id'
},
valueField: {
type: String,
default: 'name'
},
remoteKey: {
type: String,
default: 'id'
},
remoteValue: {
type: String,
default: 'name'
},
disabled: {
type: Boolean,
default: false
},
selectedTags: {
type: Array,
required: false,
default: () => [],
},
existingTags: {
type: Array,
required: false,
default: () => [],
},
limit: {
type:Number,
default: 200
},
onlyExistingTags: {
type: Boolean,
default: true
}
},
data: function () {
return {
currentTags: [],
}
},
created() {
this.currentTags=this.selectedTags;
},
components: { 'tags-input':VoerroTagsInput },
methods: {
updateItems(input) {
this.$emit('update-list', input);
},
onTagAdded(slug) {
this.$emit('tag-added', slug);
},
onTagRemoved(slug) {
this.$emit('tag-removed', slug);
},
onInitialized() {},
onTagsUpdated(slug) {},
onLimitReached() {},
onKeyDown() {},
onKeyUp(k) {},
onFocus() {},
onBlur() {},
}
}
</script>
<style>
/* The input */
.tags-input {
clear:both;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.tags-input input {
flex: 1;
background: transparent;
border: none;
}
.tags-input input:focus {
outline: none;
}
.tags-input input[type="text"] {
color: black;
}
.tags-input-wrapper-default {
padding: .5rem .25rem;
background: #fff;
border: 1px solid transparent;
border-radius: .25rem;
border-color: #dbdbdb;
}
/* The tag badges & the remove icon */
.tags-input span {
margin-right: 0.3rem;
}
.tags-input-remove {
cursor: pointer;
position: relative;
display: inline-block;
width: 0.5rem;
height: 0.5rem;
overflow: hidden;
}
.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.vue-tags-input.disabled input {
background-color: transparent;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.tags-input-remove:before, .tags-input-remove:after {
content: '';
position: absolute;
width: 100%;
top: 50%;
left: 0;
background: #5dc282;
height: 2px;
margin-top: -1px;
}
.tags-input-remove:before {
transform: rotate(45deg);
}
.tags-input-remove:after {
transform: rotate(-45deg);
}
/* Tag badge styles */
.tags-input-badge {
display: inline-block;
padding: 0.25em 0.4em;
font-size: 75%;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.25rem;
}
.tags-input-badge-pill {
padding-right: 0.6em;
padding-left: 0.6em;
border-radius: 10rem;
}
.tags-input-badge-selected-default {
color: #212529;
background-color: #f0f1f2;
}
/* Typeahead */
.typeahead-hide-btn {
color: #999 !important;
font-style: italic;
}
/* Typeahead - badges */
.typeahead-badges > span {
cursor: pointer;
margin-right: 0.3rem;
}
/* Typeahead - dropdown */
.typeahead-dropdown {
list-style-type: none;
padding: 0;
margin: 0;
position: absolute;
width: 100%;
z-index: 1000;
}
.typeahead-dropdown li {
padding: .25rem 1rem;
cursor: pointer;
}
/* Typeahead elements style/theme */
.tags-input-typeahead-item-default {
color: #fff;
background-color: #343a40;
}
.tags-input-typeahead-item-highlighted-default {
color: #fff;
background-color: #007bff;
}
</style>
<template>
<my-tags-input :existingTags="autocompleteItems"
:disabled="isDisplay"
@tag-added="addTag"
@tag-removed="removeTag"
:selectedTags="selectedTags"
@update-list="updateAutoCompleteCityItems"
key-field="id"
value-field="name"
remote-key="cityId"
remote-value="cityName"
/>
</template>
<script>
import MyTagsInput from '@/components/MyTagsInput'
export default {
components: {
MyTagsInput,
},
data() {
return {
selectedTags:[],
autocompleteItems: [],
}
},
created() {
// this.selectedTags = this.currentArea.cities
},
methods: {
addTag(slug) {
this.$emit('tag-added', slug);
},
removeTag(slug) {
this.$emit('tag-removed', slug);
},
updateAutoCompleteCityItems: function (searchValue) {
if (searchValue.length>=1) {
this.initialiseCities(searchValue);
}
},
initialiseCities(searchValue){
//This is local to my app but connects to db and search city by what auto complete key press returns..
//You would need to pass in a dummy array of cities and as per below `cityId` `cityName` iteration of `cities`
MyService.fetch('/city/search/'+searchValue)
.then((res) => {
if (res && res.data) {
res.data.forEach(function(t) {
var tt = t.id
var tn = t.name
delete t['id']
delete t['name']
t.cityId=tt
t.cityName=tn
})
this.autocompleteItems = res.data;
}
});
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment