Check only one checkbox and uncheck others using livewire - php

I'm trying to check only one checkbox at a time and others uncheck, but when I want to check a new checkbox then the previous will uncheck, and so on.
my code in blade:
#foreach($addressEmployer as $address)
<div class="col-12 col-lg-3 p-2 m-2 rounded" style="border: dashed #a1a1a1;">
<label for="check{{$address->id}}"></label>
<div class="row">
<div class="col-2 mt-5">
<input wire:model="addressSelected.{{$address->id}}"
value="{{$address->id}}"
class="form-check-input" type="checkbox"
id="check{{$address->id}}">
</div>
<div class="col-10">
<p> {{$address->province->name}} - {{$address->city->name}}</p>
<p> {{$address->address}}</p>
<a wire:click="setAddress({{$address->id}})" class="float-end"
data-bs-toggle="modal"
href="#editAddressModal"
role="button">{{__('Edit')}}</a>
<a wire:click="$emit('addressId',{{$address->id}})" class=" me-3 float-end"
data-bs-toggle="modal"
href="#deleteAddressModal"
role="button">{{__('Delete')}}</a>
</div>
</div>
</div>
#endforeach
I read the addresses from the database and display them with foreach and I want to select one of the displayed addresses.
I am looking for the right solution to this issue. Thanks if you have a solution.

When you have multiple options but want to limit selection to a single option, radio buttons are your friend.
If the previously selected radio button is not de-selecting, it suggests you haven't grouped your radio button elements correctly using the name attribute.
Here is a simplified example to get you on the right path.
Component
class AddressComponent extends Component
{
public $addresses = Address::all();
public $selectedAddressId;
public function mount()
{
$this->addresses = Address::all();
$this->selectedAddressId = 1;
}
public function render()
{
return view('livewire.address-component-view');
}
}
Component view
<div>
#foreach ($addresses as $address)
<div class="mt-1">
<input type="radio" id="{{ $address->id }}" name="address" value="{{ $address->id }}" wire:model="selectedAddressId" />
<label for="{{ $address->id }}">{{ $address->address }}</label>
</div>
#endforeach
<h3>Selected Address ID: {{ $selectedAddressId }}</h3>
</div>

I'm not shure why you're trying this with checkbox, instead of radiobutton. But maybe you can handle something like this
public $addressSelected = [];
protected $rules = [
'addressSelected.id' => 'nullable'
];
public function updatingAddressSelected($value)
{
$this->addressSelected = [];
}
// in blade add the wire:key directive to checkbox's root div
<div class="col-2 mt-5" wire:key="checkbox-id-{{ $address->id }}">
<input wire:model="addressSelected.{{$address->id}}"
value="{{$address->id}}"
class="form-check-input" type="checkbox"
id="check{{$address->id}}"
#if(in_array($address->id,$addressSelected)) checked #endif
>
</div>

Related

How to validate at least one checkbox is checked in a loop in Laravel?

I'm trying to validate my checkbox from a loop, where at least one is checked and displays an error/alert or disable the submit button instead if there is no checkbox checked. I tried putting a required method inside my checkbox, but the checkbox is in a loop that's why it requires all to be checked. That's why I tried the script code below which I found on the internet but that doesn't seem to work for me.
Below is my code in blade form
<form id="contact" action="{{url('/reservation')}}" method="post" enctype="multipart/form-data">
#csrf
<div class="row col-12">
#foreach($data as $data)
<div class="row sm-6 ml-4 mb-1" class="no-gutters" style="height:25px; width: auto;">
<p class='text-dark mr-2'><input type="checkbox" name="prod_name[]" value="{{$data->title}}" class="products product{{$data}}" onClick="checkTest()"/> {{$data->title}}</p>
<p class='text-dark'>Qty:</p><input style="width:80px; height:25px;" type="number" name="prod_qty[{{$data->title}}]" min="1" value="1" class="form-control ml-2">
<input type="hidden" name="product_fee[{{$data->title}}]" value="{{$data->price}}">
<input type="hidden" name="prod_id[{{$data->title}}]" value="{{$data->id}}">
</div>
#endforeach
</div>
<div class=" col-lg-12 mt-5">
<fieldset>
<button name="submit" type="submit" id="form-submit" class="main-button-icon">Make A Reservation</button>
</fieldset>
</div>
</div>
</form>
<script>
var minimumonechecked;
var checkboxes = $('.products').lenght;
function checkTest(xyz){
minimumonechecked = false;
for(i=0;i<checkboxes;i++){
if($('product' + i).is(':checked')){
minimumonechecked = true;
}
}
console.log(minimumonechecked)
};
</script>
This is also the code in my controller, other data such as names are also part of the form but I cut it out by focusing on the checkbox
public function reservation(Request $request)
{
if(Auth::id()){
$user_id=Auth::id();
$products = '';
$reserved_qty=0;
$product_fee=0;
$prod_id=0;
$checked_array = $request->input('prod_name', []);
$quantities = $request->input('prod_qty', []);
$fees = $request->input('product_fee', []);
$productid = $request->input('prod_id', []);
foreach($checked_array as $value){
$data = new reservation;
$data->user_id=$user_id;
$data->name=$request->name;
$data->email=$request->email;
$data->phone=$request->phone;
$data->address=$request->address;
$data->date=$request->date;
$data->time=$request->time;
$data->status="pending";
$data->productz=$request->products="{$value}";
$data->reserved_qty=$request->$reserved_qty="{$quantities[$value]}";
$data->product_fee=$request->$product_fee=$fees[$value]*$quantities[$value];
$data->prod_id=$request->$prod_id=$productid[$value];
$data->save();
}
return redirect()->back();
}else{
return redirect('/login');
}
There are a many ways to achieve your desired result, how I would approach it is as follows (note this is not exhaustive, it's a functional example).
On the client, use JavaScript to select all your product checkboxes, iterate over any found and attach event handlers to each of them which listen for the changed event (i.e. checked and unchecked). When the state of a checkbox is checked, add it to a Set so that we can track how many are selected. Based on the number of checked checkboxes, enable/disable form submission.
That theory out of the way, some code:
HTML:
<script src="https://cdn.tailwindcss.com"></script>
<div class="flex flex-col place-content-center items-center h-screen space-y-4">
<div class="flex align-items-center space-x-2">
<h1 class="underline font-bold decoration-orange-500 decoration-2">
<a href="https://stackoverflow.com/questions/73834200/how-to-validate-at-least-one-checkbox-is-checked-in-a-loop-in-laravel">
How to validate at least one checkbox is checked in a loop in Laravel?
</a>
</h1>
</div>
<div class="flex align-items-center space-x-2">
<input type="checkbox" class="products" name="products[]" id="product-a" />
<label for="product-a" class="text-sm">Product A</label>
</div>
<div class="flex align-items-center space-x-2">
<input type="checkbox" class="products" name="products[]" id="product-b" />
<label for="product-b" class="text-sm">Product B</label>
</div>
<div class="flex align-items-center space-x-2">
<input type="checkbox" class="products" name="products[]" id="product-c" />
<label for="product-c" class="text-sm">Product C</label>
</div>
<div class="flex align-items-center space-x-2">
<button class="px-4 py-2 rounded bg-orange-600 hover:bg-orange-700 text-white text-sm" id="form-submit">Submit</button>
</div>
</div>
JavaScript:
window.addEventListener('DOMContentLoaded', function () {
// get all the product checkbox elements
var productCheckboxes = document.querySelectorAll('.products');
// holder for the checked products
var checkedProducts = new Set();
// pointer to the form submit button
var formSubmitButton = document.querySelector('#form-submit');
// attach change event handlers to each of the checkboxes
productCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('change', function (e) {
e.target.checked
? checkedProducts.add(e.target.id)
: checkedProducts.delete(e.target.id);
});
});
//
formSubmitButton.addEventListener('click', function (e) {
handleClientSideValidation();
});
// do some client side validation (do not rely on this alone!)
function handleClientSideValidation() {
if (checkedProducts.size == 0) {
alert('Ugh-oh, something is foobar Captain. You need to select at least 1 product.');
return;
}
alert('Validating ...');
}
})
Example CodePen
Now lets apply the above to a Laravel example using #foreach and Eloquent models. I am going to assume you already have a Product model, migration and some data seeded.
Form HTML:
<form action="{{ route('reservation') }}" method="POST" id="products-form">
<div class="flex flex-col place-content-center items-center h-screen space-y-4">
#csrf
<div class="flex align-items-center space-x-2">
<h1 class="underline font-bold decoration-orange-500 decoration-2">
<a href="https://stackoverflow.com/questions/73834200/how-to-validate-at-least-one-checkbox-is-checked-in-a-loop-in-laravel">
How to validate at least one checkbox is checked in a loop in Laravel?
</a>
</h1>
</div>
#if ($errors->any())
<div class="px-4 py-2 bg-red-500 text-white text-sm rounded-sm">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
#foreach($products as $product)
<div class="flex align-items-center space-x-2">
<input type="checkbox" class="products" name="products[]" id="product-{{ $product->id }}" value="{{ $product->id }}" />
<label for="product-{{ $product->id }}" class="text-sm">{{ $product->title }}</label>
</div>
#endforeach
<div class="flex align-items-center space-x-2">
<button type="submit" class="px-4 py-2 rounded bg-orange-600 hover:bg-orange-700 text-white text-sm" id="form-submit">Submit</button>
</div>
</div>
</form>
As we all know you shouldn't rely soley upon client side validation, so you'll want to do some server side validation too. Once you've validated your request data, you can do whatever you want with it (I just get the products from the database in this example). I have put the code directly in a Route within web.php as I am lazy, you'd obviously use it in your ProductController function.
routes/web.php:
Route::post('/', function (Request $request) {
// perform some validation
// $validate will contain all the data that passed validation
$validated = $request->validate([
// products must be present in the request AND an array
'products' => ['required', 'array'],
// each of the products in the request, must have an ID present in the database
'products.*' => ['exists:products,id']
]);
// if we get here, validation was successfull
// do whatever you want with the $validated data
// I am just getting the Products as an example
$products = \App\Models\Product::whereIn('id', $validated['products'])->get();
// dump the Products
dd($products->all());
})->name('reservation');
Example PHP Sandbox
Quite a lot to taken in but hopefully that makes sense.
When you tick on checkbox, you need to count all checkboxes that have been checked before.
If at least checkbox is checked , you'll set disabled property on submit button is true and vice verse
<script>
$('.products').on('change', function() {
$('#form-submit').prop('disabled', $('.products:checked').length > 0);
});
</script>

Submitting data in a Livewire child view using its <form> in the parent view

I have a parent view edit.blade.php which has a form. The form has a #livewire() for edit-step.blade.php, the child component.
edit-step.blade.php has a foreach loop that renders the input fields. At one point, foreach will loop three input fields. The submit button is in the parent view edit.blade.php. On submitting, data from the last input field is the only one being submitted. How do I make data from all the input fields be submitted ?
edit.blade.php file:
<form method="post" action="{{route('todo.update', $todo->id)}}" class="py-5">
#csrf
#method('patch')
<div class="py-1"><input type="text" name="title" value="{{$todo->title}}" class="py-2 px-2 border rounded" placeholder="Title" /></div>
<div class="py-1">
<textarea name="description" class="p-2 rounded border" placeholder="Description">{{$todo->description}}</textarea>
</div>
<div class="py-2">
#livewire('edit-step', ['steps' => $todo->steps])
</div>
<div class="py-1"><input type="submit" value="Update" class="p-2 border rounded" /></div>
</form>
edit-step.blade.php file:
#foreach($steps as $step)
<div class="flex justify-center py-2" wire:key="{{$loop->index}}" >
<input type="text" name="step_" class="py-1 px-2 border rounded" placeholder="{{ 'Describe Step '.($loop->index + 1) }}" #if ( is_object($step) ) value="{{ $step->name }}" #endif />
<span class="fas fa-times text-red-400 p-2" wire:click="remove({{$loop->index}})"/>
</div>
#endforeach
Here is an example from my recent project. I have managed this with a single livewire component.
In Livewire Component;
public $entries = [];
public $date;
public function mount()
{
$this->date = now()->format('Y-m-d');
$this->entries=[
[
'name'=>'',
'amount'=>'',
],
[
'name'=>'',
'amount'=>'',
]
}
Now, in edit.blade.php ;
<input type="date" wire:model="date">
#foreach($entries as $key=>$entry)
<div wire:key="{{'entry'.$key}}">
<div>
<input type="text" wire:model="entries.{{$key}}.name">
</div>
<div>
<input type="number" wire:model="entries.{{$key}}.amount">
</div>
</div>
#endforeach
Now, again in livewire component for saving;
public function save()
{
foreach($this->entries as $entry){
Transaction::create([
'name'=>$entry['name'],
'amount'=>$entry['amount']
)];
}
//Notify User
}
However, if for any reason you need two livewire component to manage a same form, you can emit from a component and listen in another component.
For example in emitting component;
public function save(){
$this->emit('entryMade', $amount);
}
Now in listening component;
protected $listeners = ['entryMade'];
public function entryMade($amount)
{
// Do anything with $amount
}

Laravel Livewire Select2 Multiple sellect issue

Product variation Color first time is disable after enable can select color.
without wire:ignore after select color its disappear from select option.
If I use wire:ignore
{{ $colors_active== 0 ?'disabled':'' }}
disable is not removed, it's still disabled.
product.blade.php
<div class="row g-3 align-center">
<div class="col-lg-3">
<div class="form-group">
<input class="form-control" type="text" value="Colors" readonly>
</div>
</div>
<div class="col-lg-8">
<div class="form-group">
<select class="form-control color-select2" multiple style="width: 100%" {{ $colors_active== 0 ?'disabled':'' }} >
#foreach (App\Models\Admin\Color::orderBy('name', 'asc')->get() as $key => $color)
<option value="{{$color->code}}">
{{$color->name}}
</option>
#endforeach
</select>
</div>
</div>
<div class="col-lg-1">
<div class="form-group">
<div class="form-control-wrap">
<label class="c-switch c-switch-pill c-switch-opposite-success">
<input wire:model="colors_active" class="c-switch-input" type="checkbox" value="1" ><span class="c-switch-slider"></span>
</label>
</div>
</div>
</div>
</div>
Product.php Component
{
public $colors_active;
public $choice_attributes = [];
public $colors = [];
public function mount(){
}
public function render()
{
return view('livewire.admin.product.product')->layout('admin.layouts.master');
}
}
Livewire will ignore any changes to anything marked with wire:ignore, so naturally it will not re-render anything when its ignored.
You can solve this by using Apline.js, and entangle the $colors_active property to an attribute in Alpine.js. Entangle means that when Livewire updates the variable in its backend, Alpine updates its variable too - and vice-versa (Alpine.js updates Livewire when the variable is changed). Basically, its kept in sync between the two.
Then, you can make Alpine.js dynamically bind the disabled property of your select-element based on that variable.
<div x-data="{ 'colorsActive': #entangle('colors_active') }">
<select
class="form-control color-select2"
multiple
style="width: 100%"
wire:ignore
x-bind:disabled="colorsActive == 0"
>
#foreach (App\Models\Admin\Color::orderBy('name', 'asc')->get() as $key => $color)
<option value="{{ $color->code }}">
{{ $color->name }}
</option>
#endforeach
</select>
</div>
This is the way I use to approach this kind of solutions with Livewire, without Alpine because unfortunately I haven't learn it.
In the blade component:
<div class="col d-flex display-inline-block">
<label>Device</label>
<select {{ $customer ? '' : 'disabled' }} wire:model="selectedItem" class="form-control contact_devices_multiple" multiple="multiple" data-placeholder="Select" style="width: 100%;">
#foreach($devices as $device)
<option value="{{ $device->id }}">{{ $device->alias }}</option>
#endforeach
</select>
</div>
<script>
window.loadContactDeviceSelect2 = () => {
$('.contact_devices_multiple').select2().on('change',function () {
livewire.emitTo('contact-component','selectedItemChange',$(this).val());
});
}
loadContactDeviceSelect2();
window.livewire.on('loadContactDeviceSelect2',()=>{
loadContactDeviceSelect2();
});
</script>
in component
public $customer = null;
public $selectedItem = [];
public function hydrate()
{
$this->emit('loadContactDeviceSelect2');
}
public $listeners = [
'selectedItemChange',
];
public function selectedItemChange($value)
{
dd($value);
}

Adding a div row for a new row in Laravel

I am beginner in Laravel. I make my project in Laravel 8.
I have this code:
#foreach($productIngredients as $productIngredient)
#php
if($selectedProductIngredients->contains('ingredient_id', $productIngredient->id) === true){
$item = \App\Models\SelectedProductIngredient::where('product_id', $product->id)->where('ingredient_id', $productIngredient->id)->first();
$weight = $item->weight;
} else {
$weight = null;
}
#endphp
<div class="col-6">
<div class="form-check py-2">
<input id="productIngredientId-{{ $productIngredient->id }}"
class="form-check-input enableInput" style="margin-top:10px"
name="productIngredient[]" type="checkbox"
value="{{ $productIngredient->id }}"
#if($selectedProductIngredients->contains('ingredient_id', $productIngredient->id) === true) checked #endif>
<label class="form-check-label" for="flexCheckChecked">
{{ $productIngredient->name }} [{{ $productIngredient->short_name }}]
</label>
<input id="productIngredient-{{ $productIngredient->id }}" type="text"
name="productIngredient-{{ $productIngredient->id }}" maxlength="10"
class="form-control weight-input weightMask"
style="width:100px;display: inline; margin-left:20px" placeholder=""
value="{{ $weight }}">
</div>
</div>
#endforeach
It's work fine.
I would like there to be 2 records in 1 row.
So I would like to add at the beginning and close div in case of the last record
How can I do this?
Please help me.
Do you know about the Laravel collection? It can help you.
You can use chunk method, it breaks the collection into multiple, smaller collections of a given size:
#foreach($productIngredients->chunk(2) as $chunk)
<div class="row">
#foreach($chunk as $productIngredients)
<div class="col-6">
...
</div>
#endforeach
</div>
#endforeach

Cannot get request object

Grettings.
I'm trying to call an index view from itself, to look for a person and displaying results to the left.
But when I call the view and send data It always get null, could you please give me a clue. I've even called the store function and request is always null.
It should be a modal window to get the request object? What should I do If I wanted to show the windows as I'm doing it?
My routes
Route::get('registroaccesos/destinationSearchGet/', 'RegistroAccesosController#destinationSearchGet')->name('registroaccesos.destinationSearchGet');
Route::post('registroaccesos/destinationSearchPost/', 'RegistroAccesosController#destinationSearchPost')->name('registroaccesos.destinationSearchPost');
The controller
public function destinationSearchGet(){
$headData = array('pageTitle' => 'Admin Home - View all destinations');
return view('registroaccesos.index', $headData);
}
public function destinationSearchPost(Request $request){
$headData = array('pageTitle' => 'Admin Home - Search results');
$formData = $request->input('strPatron');
dd($formData);
// $data = ParentRegionList::destinationSearch($formData);
return view('registroaccesos.index', $headData);//->with(compact('data'))
}
The view
Part of the code of the view
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Acciones</span>
<a class="d-flex align-items-center text-muted" href="#">
<span data-feather="plus-circle"></span>
</a>
</h6>
<div class="form-group">
<label for="strSearch" class="col-form-label">Patrón de búsqueda</label>
<select name="strSearch" class="form-control">
<option value="1" selected> Código del usuario</option>
<option value="2" > Nombre del usuario</option>
</select>
</div>
<div class="form-group">
<input placeholder="Patrón de búsqueda"
id="strPatron"
required
name="strPatron"
spellcheck="false"
class="form-control"
value="Valor"
/>
</div>
<button class="btn btn-sm btn-outline-secondary"
onclick="
event.preventDefault();
document.getElementById('search-form').submit();
"
>Buscar</button>
<form id="search-form" action="{{ route('registroaccesos.store','el resultado' ) }}" method="POST" style="display: none;">
<!-- <input type="hidden" name="_method" value="delete">-->
{{ csrf_field() }}
</form>
The result
Well your <input> with name="strPatron" is not in your <form> so it will not get submitted when you submit the form. You need to have all the input elements inside the form or they won't get sent with the POST request.
The way you've got it right now only the CSRF field in your form is getting submitted. You can check this by doing a dd($request->all()) in your controller.

Categories