added auto complete for tags

master
A1Gard 1 day ago
parent 893ff16735
commit 01071196df

@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Mpdf\Tag;
class TagController extends Controller
{
//
public function search($q)
{
// // Check if $q contains any non-Latin characters
// if (preg_match('/[^\x20-\x7E]/', $q)) {
// // If it contains non-Latin characters, encode it
// $q =trim( json_encode($q),' "');
// }
// Perform the search
$tags = \Spatie\Tags\Tag::where('name->' . config('app.locale'), 'like', '%' . $q . '%')->limit(10)->pluck('name');
return ['OK' => true, 'data' => $tags];
}
}

@ -7,9 +7,18 @@
</span> </span>
<input type="text" v-model="tag" :id="xid" <input type="text" v-model="tag" :id="xid"
@keyup.enter.prevent="addTag" @keyup.enter.prevent="addTag"
@keyup="checkAutoComplete"
@keyup.down.prevent="incIndex"
@keyup.up.prevent="decIndex"
@focus="disableSubmit" @focus="disableSubmit"
@blur="enableSubmit" :placeholder="xtitle"> @blur="enableSubmit" :placeholder="xtitle">
<input :name="xname" type="hidden" :value="tags.join(splitter)"> <input :name="xname" type="hidden" :value="tags.join(splitter)">
<ul id="search-list" v-if="searchList.length > 0">
<li v-for="(word,i) in searchList" @click="selectTag(i)" :class="selectedIndex == i?'selected':''">
<i class="ri-price-tag-3-line float-start mx-2" ></i>
{{word}}
</li>
</ul>
</div> </div>
</div> </div>
</template> </template>
@ -26,6 +35,8 @@ export default {
return { return {
tag: '', tag: '',
tags: [], tags: [],
searchList:[],
selectedIndex: -1,
} }
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
@ -58,6 +69,10 @@ export default {
}, },
type: Function, type: Function,
}, },
autoComplete:{
default: '',
type: String,
}
}, },
mounted() { mounted() {
if (this.modelValue != null) { if (this.modelValue != null) {
@ -72,9 +87,18 @@ export default {
computed: {}, computed: {},
methods: { methods: {
addTag(e) { addTag(e) {
if (this.selectedIndex > -1 && (this.selectedIndex + 1) < this.searchList.length ){
this.tags.push(this.searchList[this.selectedIndex]) ;
this.tag = '';
this.searchList = [];
this.checkDuplicate();
this.$emit('update:modelValue', this.tags.join(this.splitter));
return;
}
if (this.tag.trim()) { // Check if the input is not empty if (this.tag.trim()) { // Check if the input is not empty
this.tags.push(this.tag.trim()); // Add the trimmed tag this.tags.push(this.tag.trim()); // Add the trimmed tag
this.tag = ''; // Reset the input this.tag = ''; // Reset the input
this.checkDuplicate();
this.$emit('update:modelValue', this.tags.join(this.splitter)); this.$emit('update:modelValue', this.tags.join(this.splitter));
} }
}, },
@ -89,6 +113,32 @@ export default {
rem(tag){ rem(tag){
this.tags.splice(this.tags.indexOf(tag),1); this.tags.splice(this.tags.indexOf(tag),1);
this.$emit('update:modelValue', this.tags.join(this.splitter)); this.$emit('update:modelValue', this.tags.join(this.splitter));
},
async checkAutoComplete(e){
if (this.autoComplete !== '' && this.tag.length > 2){
let resp = await axios.get(this.autoComplete + this.tag);
if (resp.data.OK == true){
this.searchList = resp.data.data;
}
}
},
selectTag(i,e){
this.tags.push(this.searchList[i]) ;
this.tag = '';
this.searchList = [];
this.checkDuplicate();
this.$emit('update:modelValue', this.tags.join(this.splitter));
},
incIndex(){
this.selectedIndex++;
},
decIndex(){
this.selectedIndex--;
},
checkDuplicate(){
this.tags = [...new Set(this.tags)];
} }
} }
} }
@ -126,4 +176,23 @@ export default {
.tag-select i:hover { .tag-select i:hover {
color: red; color: red;
} }
#search-list{
padding: 0;
list-style: none;
li{
border-bottom: 1px solid silver;
padding: 4px;
&:last-child{
border-bottom: 0;
}
&.selected{
background: olive;
}
}
border: 1px solid grey;
border-radius: 6px;
}
</style> </style>

@ -94,6 +94,7 @@
@if(isset($item)) @if(isset($item))
xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}" xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}"
@endif @endif
auto-complete="{{route('v1.tag.search','')}}/"
></tag-input> ></tag-input>
</div> </div>

@ -57,6 +57,7 @@
@if(isset($item)) @if(isset($item))
xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}" xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}"
@endif @endif
auto-complete="{{route('v1.tag.search','')}}/"
></tag-input> ></tag-input>
{{-- <input type="text" name="tags" class="taggble" @if(isset($item))--}} {{-- <input type="text" name="tags" class="taggble" @if(isset($item))--}}
{{-- value="{{implode(',',$item->tag_names)}}"--}} {{-- value="{{implode(',',$item->tag_names)}}"--}}

@ -28,6 +28,7 @@
@if(isset($item)) @if(isset($item))
xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}" xvalue="{{old('title',implode(',,',$item->tags->pluck('name')->toArray()??''))}}"
@endif @endif
auto-complete="{{route('v1.tag.search','')}}/"
></tag-input> ></tag-input>
</div> </div>

@ -41,4 +41,7 @@ Route::prefix('v1')->name('v1.')->group(
Route::apiResource('web', \App\Http\Controllers\Api\HomeController::class)->only('index'); Route::apiResource('web', \App\Http\Controllers\Api\HomeController::class)->only('index');
Route::apiResource('products' , \App\Http\Controllers\Api\ProductController::class)->only('index'); Route::apiResource('products' , \App\Http\Controllers\Api\ProductController::class)->only('index');
Route::get('tag/search/{q}', [\App\Http\Controllers\Api\TagController::class, 'search'])->name('tag.search');
}); });

Loading…
Cancel
Save