with livewire 1.3 / alpinejs 2.x.x I make listing of data with filter text and selection inputs and clicking on “Search” button I need to run search when “Search” button is clicked. But search is run when text/selection input lose focus without clicking on “Search” button. I see it by form's wire:loading block and 1 line in log file, which I trigger in render method That is not what I need : I need to run render method only clicking on “Search” button. I tried to use alpinejs, but failed... In component app/Http/Livewire/Admin/AppNews.php I have:
<?php
namespace App\Http\Livewire\Admin;
use Carbon\Carbon;
use Livewire\Component;
use App\News;
use Livewire\WithPagination;
use Livewire\WithFileUploads;
class AppNews extends Component
{
use WithPagination;
use WithFileUploads;
public $filters = [
'title' => '',
'published' => '',
];
];
public $uploaded_file_name;
public $uploadedImageFilenameData;
public $uploadedNewsImage;
protected $listeners = ['fileUpload' => 'handleFileUpload'];
public $current_news_id;
public $updateMode = 'browse';
public function render()
{
\Log::info('-1 NewsRENDER $this->filters ::' . print_r($this->filters, true));
$news_rows_count = News
::getByTitle($this->filters['title'], true)
->getByPublished($this->filters['published'], true)
->count();
$backend_per_page = Settings::getValue('backend_per_page', CheckValueType::cvtInteger, 20);
$this->emit('app_news_opened', ['mode' => 'browse', 'id' => null]);
$newsPublishedValueArray = SetArrayHeader([['key' => '', 'label' => ' -Select published- ']], News::getNewsPublishedValueArray(true));
$newsDataRows = News
::getByTitle($this->filters['title'], true)
->getByPublished($this->filters['published'], true)
->with('creator')
->orderBy('news.created_at', 'desc')
->paginate($backend_per_page);
$newsDataIds = [];
foreach ($newsDataRows as $nextNews) {
$newsDataIds[] = $nextNews->id;
}
return view('livewire.admin.app-news.container', [
'newsDataRows' => $newsDataRows,
'newsDataIds' => $newsDataIds,
'form' => $this->form,
'news_rows_count' => $news_rows_count,
'newsPublishedValueArray' => $newsPublishedValueArray,
]);
}
and in the template resources/views/livewire/admin/app-news/container.blade.php :
<article class="admin_page_container">
<div class="card form-admin-news">
<div class="card-body card-block">
<div class="spinner-border" role="status" wire:loading>
<span class="sr-only">Loading...</span>
</div>
...
<fieldset class="bordered text-muted p-2 m-2" x-data="{ title: '{{$filters['title']}}', published: '{{$filters['published']}}' ,
publishedItems: <?php print str_replace('"',"'",json_encode( $newsPublishedValueArray) ) ?> } ">
<div> $filters::{{ var_dump($filters) }}</div>
title::<div x-html="title"></div>
published::<div x-html="published"></div>
<legend class="bordered">Filters</legend>
<dl class="block_2columns_md m-0 p-2">
<dt class="key_values_rows_label_13">
<label class="col-form-label" for="temp_filter_title">
By title
</label>
</dt>
<dd class="key_values_rows_value_13" >
<div class="content_with_right_button">
<div
class="content_with_right_button_left_content"
wire:model.lazy="filters.title"
>
<input
class="form-control admin_control_input"
type="text"
x-model="title"
x-on:blur="$dispatch('input', title)"
id="title"
>
</div>
<div class="content_with_right_button_right_button pl-2">
<button class="btn btn-outline-secondary nowrap_block" wire:click="makeSearch( )">
{!! $viewFuncs->showAppIcon('filter') !!}Search
</button>
</div>
</div>
</dd>
</dl>
<dl class="block_2columns_md m-0 p-2">
<dt class="key_values_rows_label_13">
<label class="col-form-label" for="temp_filter_published">
By published
</label>
</dt>
<dd
class="key_values_rows_value_13"
wire:model.lazy="filters.published"
>
<select
x-model="published"
x-on:blur="$dispatch('select', published)"
id="published"
class="form-control editable_field admin_control_input"
>
<template x-for="nextPublishedItem in publishedItems">
<option :value="nextPublishedItem.key" x-text="nextPublishedItem.label"></option>
</template>
</select>
@error('form.published')
<div class="validation_error">{{ clearValidationError($message,['form.'=>'']) }}</div> @enderror
</dd>
</dl>
</fieldset> <!-- Filters -->
...
@endif {{-- @if($updateMode=='browse')--}}
@endif {{-- @if($updateMode=='browse')--}}
@if(count($newsDataRows) > 0)
<div class="table-responsive table-wrapper-for-data-listing" x-data="selectedNewsIdsBoxXData()">
<table>
...
</table>
</div> <!-- <div class="table-responsive table-wrapper-for-data-listing"> -->
@endif {{-- @if(count($newsDataRows) > 0) --}}
@endif {{-- @if($updateMode=='browse') --}}
</div> <!-- <div class="card-body card-block"> -->
</div> <!-- <div class="card"> -->
</article> <!-- page_content_container -->
Which is the valid way?
Modified BLOCK 2:
I try another way with using of alpinejs2 : I try to use it in this case, as when public var of component is changed: with dispatch methid when button “Search” is clicked
<div class="card form-admin-facilities" x-data="adminFacilitiesComponent()">
...
filter_name: {{$filter_name}}<br>
...
temp_filter_name: <span x-html="temp_filter_name"></span><br>
...
<fieldset class="bordered text-muted p-2 m-2">
<legend class="bordered">Filters</legend>
<div class="content_with_right_button" wire:model.lazy="filter_name">
<div class="content_with_right_button_left_content" >
<input
class="form-control admin_filter_input"
x-model="temp_filter_name"
type="text"
>
</div>
<div class="content_with_right_button_right_button pl-2" >
<button class="btn btn-outline-secondary" @click="$dispatch('input', temp_filter_name)" type="button">Search
</button>
<!-- In more complicated form can be several filter fields : text and select inputs -->
</div>
</div>
</fieldset> <!-- Filters -->
...
<script>
function adminFacilitiesComponent() {
return {
temp_filter_name:'',
and in the component I defined public $filter_name var, which is used in render method :
class Facilities extends Component
{
public $form= [
'name'=>'',
'descr'=> '',
'created_at'=> '',
'is_reopen' => false,
];
public $current_facility_id;
public $filter_name= '';
public $updateMode = 'browse';
public function render()
{
\Log::info( '-1 render Facilities $this->filter_name ::' . print_r( $this->filter_name, true ) );
$this->facility_rows_count = Facility
::getByName($this->filter_name, true)
->count();
$backend_per_page = Settings::getValue('backend_per_page', CheckValueType::cvtInteger, 20);
return view('livewire.admin.facilities.container', [
'facilityDataRows' => Facility
::orderBy('created_at', 'desc')
->getByName($this->filter_name, true)
->paginate($backend_per_page),
'facility_rows_count'=> $this->facility_rows_count
]);
}
But it does not work as I expect : entering value in text input when this input lose focus form is rendered again. I expected form to be rendered only when I click on “Search” button and form will be rendered with new entered value. I do not use blur event for text input and do not understand why the form is rendered when this input lose focus?
Modified BLOCK 3: Using x-ref= I do :
<div class="content_with_right_button" wire:model.lazy="filter_name">
<div class="content_with_right_button_left_content" >
<input
class="form-control admin_filter_input"
x-model="temp_filter_name"
x-ref="searched"
type="text"
> 1111111
</div>
<div class="content_with_right_button_right_button pl-2" >
<button class="btn btn-outline-secondary nowrap_block" wire:click="makeSearch(this.$refs.searched)" type="button">
Search
</button>
</div>
</div>
But I got error clicking on search button:
VM1983:6 Uncaught TypeError: Cannot read property 'searched' of undefined
at eval (eval at parseOutMethodAndParams (directive.js:55), <anonymous>:6:27)
at _default.parseOutMethodAndParams (directive.js:55)
Looks like it is impossible to use this.$refs. value in
wire:click="makeSearch .
I need to trigger component method
public function makeSearch($search_value='')
{
and send entered value into it. Looks like the way I tried was invalid. If there is a valid way?
Thanks!