How do I set Algolia to not return any results if the query is blank Laravel & Vue Instant Search - laravel

Hey I use Algolia on my new Laravel project but I get into this
that Algolia displays all data that I have " Titel - description ".
What I want is only display result when I type something in the search box.
my Html Code
<div id="app">
<!-- Components will go here -->
<ais-index app-id="{{ config('scout.algolia.id') }}"
api-key="{{ env('ALGOLIA_SEARCH') }}"
index-name="posts">
<ais-search-box placeholder="Find products..."></ais-search-box>
<ais-results>
<template slot-scope="{ result }">
<div>
<h4>#{{ result.progName }}</h4>
<ul>
<li>#{{ result.description }}</li>
</ul>
</div>
</template>
</ais-results>
</ais-index>
</div>
Post Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
//
use Searchable;
}

You should replace ais-results by a component which hides it based on the query. The component looks something like this:
<!-- MyResults.vue -->
<template>
<div v-if="query.length > 0">
<slot name="header"></slot>
<slot name="default" v-for="(result, index) in results" :result="result" :index="index">
{{index}}. Result 'objectID': {{ result.objectID }}
</slot>
<slot name="footer"></slot>
</div>
</template>
<script>
import { Component } from 'vue-instantsearch';
export default {
mixins: [Component],
computed: {
query() {
return this.searchStore.query;
},
results() {
return this.searchStore.results;
},
},
};
</script>
Then replace your usage for ais-results with your own my-results component:
<div id="app">
<!-- Components will go here -->
<ais-index app-id="{{ config('scout.algolia.id') }}"
api-key="{{ env('ALGOLIA_SEARCH') }}"
index-name="posts">
<ais-search-box placeholder="Find products..."></ais-search-box>
<my-results>
<template slot-scope="{ result }">
<div>
<h4>#{{ result.progName }}</h4>
<ul>
<li>#{{ result.description }}</li>
</ul>
</div>
</template>
</my-results>
</ais-index>
</div>

Related

Livewire nestable is resetting order on drop

using the following library to add sorting and nesting https://www.hesamurai.com/nested-sort/latest, I'm also using the pre-rendered list option to populate the items (https://www.hesamurai.com/nested-sort/latest/pre-rendered).
Now my html structure looks like the following:
<div x-data class="pageContent__content__components mb10">
<span class="subTitle">Menu items</span>
<ol x-init="initSort($refs.draggable)" x-ref='draggable' id="draggable"
class='nested-sort nested-sort--enabled'>
#foreach($navigation->navigation_items as $item)
<li wire:key='{{ $item->id }}' draggable='true'
data-id="{{ $item->id }}"> {{ $item->navigatable->page_name ?? $item->navigatable->blog_title }}
<i wire:click="showAlert('{{ $item->id }}')"
class="fa-solid fa-trash-can"></i>
</li>
#if($item->children->count() > 0)
<ol data-id="{{ $item->id }}">
#foreach($item->children as $child)
<li draggable='true'
data-id="{{ $child->navigatable->id }}"> {{ $child->navigatable->page_name ?? $child->navigatable->blog_title }}
<i wire:click="showAlert('{{ $child->navigatable->id }}')"
class="fa-solid fa-trash-can"></i>
</li>
#endforeach
</ol>
#endif
#endforeach
</ol>
</div>
With the scripts being included at the bottom of the page
#push('scripts')
#once
<script src="https://cdn.jsdelivr.net/npm/nested-sort#5/dist/nested-sort.umd.min.js"></script>
<script type='text/javascript'>
function initSort(ref) {
return {
nested: new NestedSort({
el: ref,
actions: {
onDrop: function(data) {
#this.
call('saveMenuOrder', data);
},
},
}),
};
}
</script>
#endonce
#endpush
Now, adding and removing items to the list works as intended, but reordering or nesting any item causes livewire to reset the list to it's initial state.
If I where to add a wire:ignore to the <ol> that technically fixes the issue of livewire updating the DOM, but that also means that, when adding or removing items it no longer updates the list without manually refreshing the page.
My backend component looks like this:
// the model containing the items to be displayed (via a HasMany relation)
public NavigationModel $navigation;
// the method that is called everytime the onDrop action fires (the $data array contains the new order of elements)
public function saveMenuOrder(array $data): void
{
foreach ($data as $menuItem) {
$menuItemObject = $this->navigation->navigation_items->find(
$menuItem['id']
);
$menuItemObject->order = $menuItem['order'];
if (isset($menuItem['parent'])) {
$menuItemObject->parent_id = $menuItem['parent'];
} else {
$menuItemObject->parent_id = null;
}
$menuItemObject->save();
}
}
And that's basically it for the component, all I want is for livewire to update the list without messing up the DOM elements created by the library.
any ideas?
alpineJS is also installed, if that's a better solution that's also accepted.
thanks!
--- Edit
What I currenly have:
I converted the laravel foreach to an alpine x-for:
<div class="pageContent__content" style="grid-area: unset">
<div x-data='initSort($refs.draggable)'
wire:ignore
class="pageContent__content__components mb10">
<span class="subTitle">Menu items</span>
<ol class='nested-sort' x-ref='draggable' id="draggable">
<template x-for="item in items">
<li draggable="true" :data-id='item.id'>
<div class='nested-sort-item'>
<div class='nested-sort-item__text' x-text='item.text' />
<div class='nested-sort-item__actions'>
<button type='button' class='nested-sort-item__actions__button'
#click='$wire.showAlert(item.id)'
>
<i class='fas fa-trash-alt'></i>
</button>
</div>
</div>
</li>
</template>
</ol>
</div>
</div>
and rewrote the init function:
function initSort(ref) {
return {
navigation_items: #js($this->navigation_items),
get items() {
return this.navigation_items;
},
init() {
new NestedSort({
el: ref,
actions: {
onDrop: function(data) {
},
},
});
},
};
}
Now I can't seem to figure out how to access the navigation_items inside of my onDrop action, simply using this.navigation_items or this.items console.logs undefined.

Laravel Vue Loading Side Bar Menu API

I am getting menu like below from api request with laravel vue.
{"data":[{"id":67,"slug":"link","name":"Dashboard","href":"\/","hasIcon":true,"icon":"mdi mdi-home-account","iconType":"coreui","sequence":1}]}
and my componant is below and displaying well but click event not woking , when i mannully put this json data --> menu then every thing working good. so i think mounted is not working as per expectation in this senario. i tried like passing it from another component as props , then putting it in data --> menu but not working as well any idea ?
<template>
<div class="vertical-menu">
<div data-simplebar="init" class="h-100 mm-show">
<div id="sidebar-menu">
<ul class="metismenu list-unstyled" id="side-menu">
<li v-for="(item, index) in menu" :key="index">
<router-link :to="item.href ? item.href : ''" :class="item.slug === 'dropdown' ? 'has-arrow' : '' ">
<i :class="item.icon"></i>
<span :data-key="item.datakey">{{item.name}}</span>
</router-link>
<ul class="sub-menu" aria-expanded="false">
<li v-for="subItem in item.elements" :key="subItem.name" >
<router-link :to="subItem.href ? subItem.href : ''"> {{subItem.name}} </router-link>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name:"DashboardLeftBar",
props:['app_base_url'],
data(){
return {
menu: null
}
},
mounted(){
this.menuSideBar();
},
methods:{
menuSideBar(){
let token= localStorage.getItem('jwt');
let crl=JSON.parse(localStorage.getItem('user')).crl;
axios.post(myconstant.APPICATION_API_URL+'/getmenu',{
token: token,
crl: crl,
}).then((response) => {
this.menu = response.data.data;
});
}
}
}
</script>

Vue.js 3 - Add list items from component dynamically

I am new to vue, I found some examples but I could not reproduce in my situation.
I have some inputs user will fill out and once it clicks the button, the information will populate a list of items. I am trying to crete < li > with a OrderListItem component. But I am getting this error:
runtime-core.esm-bundler.js?5c40:217 Uncaught ReferenceError: machines is not defined
at eval (OrderListItem.vue?fb66:14)
Here is the form
<template>
<div>
<div class="flex flex-col mb-4 md:w-full m-1">
<label for="planter_model_id">Planter</label>
<select v-model="registration.planter_model_id" name="planter_model_id">
<option disabled selected>Planter</option>
<option v-for="planter in planters" :key="planter" :value="planter.id">{{planter.brand.name}} {{planter.name }}</option>
</select>
</div>
<div class="flex flex-col mb-4 md:w-full m-1">
<label class=" for="lines">Lines</label>
<Input v-model="registration.lines" type="number" name="lines" />
</div>
<Button type="button" #click="addItemOrder">Add</Button>
</div>
<div>
<ul>
<OrderListItem :machines="machines" />
</ul>
<div>
</template>
Here is my code
export default {
components: {
OrderListItem,
Button,
},
props: {
planters:{
type:Array,
required: true
},
},
data() {
return {
machines: [], //this what I wish to be passed to OrderListItem component
registration:{
lines:null,
planter_model_id:null,
},
}
},
methods:{
addItemOrder(){
let item = {}
item.planter_model_id = this.registration.planter_model_id
item.lines = this.registration.lines
this.machines.push(item)
}
}
};
And here is my OrderListItem component that I created on another file:
<template>
<li v-for="machine in machines" :key="machine">
<div class="flex-initial w-3/5">
<p>Planter: {{machine.planter_model_id}}</p>
<p>Lines: {{machine.lines}}</p>
</div>
</li>
</template>
<script>
export default {
name: 'OrderListItem',
props:{
machines,
}
}
</script>
I don’t know if it is relevant but I am using vue3 and laravel.
I am very newbie here and from what I learned I think if machines array was a prop I would be able to access it on my component. But I will dynamically add a and remove itens from machines array and I think props receive data from server so It should not be declared there, that why I declared inside data().
Thanks =)
You should define the prop by adding its type and default value :
export default {
name: 'OrderListItem',
props:{
machines:{type:Array,default:()=>[]},
}
}

Error while making a multiselect using vue-select

I am using vue-select in my project along with tabulator. I was able to fetch data from json file and view it. But when selecting the options i get an error saying " Component emitted event "option:selecting" but it is neither declared in the emits option nor as an "onOption:selecting" prop. ". I could not resolve this error after multiple try. Below is the code.
**<template>
<form>
<div class="container h-25 w-10/12 mx-auto pb-3 border 2 border-gray-300 flex flex-col rounded-md items-left bg-gray-100" >
<label class="px-3 py-1 w-10/12 text-xs text-black font-medium">Employee</label>
<div class="px-2">
<v-select v-model="Selected" multiple :options="options" label="Employee" placeholder="---SELECT---" class="style-chooser"></v-select>
</div>
<!-- <span>Selected: {{ Employee_Id }}</span> -->
</div>
</form>
<!-- <ul><li v-for="item in datas" :key="item.Employee">{{ item.Employee }}</li></ul> -->
</template>
<script>
import dataset from './dataset.json'
export default {
data(){
return {
openCard: false,
Selected: ""
}
},
computed: {
options: () => dataset
},
methods:{
open(){
this.openCard = ! this.openCard
},
},
}
</script>**
Your help is highly appreciated la.

Vuejs preserve element attributes

My case looks like this:
Laravel template:
<div class="block-id" is="Header">
<span>ID #3265872</span>
<ul class="tools">
<li>History</li>
<li>TOP</li>
</ul>
<button>Check</button>
</div>
The vuejs component looks just the same
<template>
<div class="block-id">
<span>ID #{{ids.id}}</span>
<ul class="tools">
<li><a>History</a></li>
<li><a>TOP</a></li>
</ul>
<button>Check</button>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
export default {
name: "Header",
computed: {
...mapGetters('global', [
'ids'
])
}
}
</script>
The problem is that when I render the component the href attribute is gone. So is there any way to preserve the href attribute in a element?

Resources