Laravel set class if radio button selected - laravel

I have these radio buttons:
It's a separate Laravel blade component.
#props(['active'])
#php
$classes = ($active ?? false)
? 'group relative border bg-white py-3 px-4 flex items-center justify-center text-black text-sm font-semibold uppercase focus:outline-none sm:flex-1 shadow-sm cursor-pointer transition duration-150 ease-in-out'
: 'group relative border py-3 px-4 flex items-center justify-center text-gray-300 text-sm font-semibold uppercase focus:outline-none sm:flex-1 shadow-sm cursor-pointer duration-150 ease-in-out';
#endphp
<label {{ $attributes->merge(['class' => $classes]) }}>
<input type="radio" name="size" value="{{ $slot }}" class="sr-only">
<span> {{ $slot }} </span>
<span class="absolute -inset-px pointer-events-none" aria-hidden="true"></span>
</label>
I call it on a different page like so:
<x-product-size>XS</x-product-size>
How do I change the variable if it's selected? I can only find solutions on changing it depending on the route by doing something like this:
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>

You can use JS for this purpose.
add an id to your radio input for example radioID.
<input type="radio" id="radioID" name="size" value="{{ $slot }}" class="sr-only">
and:
<script>
$(document).ready(function () {
$('#radioID').on('change', function () {
var selected = this.value;
if(selected == "XS") // or a variable
var slot = "some data";
{
$("#spanID").append(' + slot + ');
}
});
});
</script>
If you want to add active to a div, span or something other you can do it like this using their CLASS or ID:
$('.someclass').first().addClass('active');
$('#someid').first().addClass('active');

Related

How to pass Model as parameters to the Wire (Livewire Laravel)

In the button, I can't pass Model product as parameters to the Wire (Livewire Laravel).
I have two function initiateEdit first in model stockin and the other in model product.
in this code only call the function that found in the stockin model but i want the function in the product model.
how to call the function for the specific model ?
<button
class="flex items-center p-2 text-sm font-medium leading-5 text-center text-white transition-colors duration-150 bg-gray-600 border border-transparent rounded-lg active:bg-gray-600 hover:bg-gray-700 focus:outline-none focus:shadow-outline-gray"
wire:click="$emit('initiateEdit', {{ $product['id'] }} )"
title="{{ __('Edit') }}">
<x-heroicon-o-pencil class="w-5 h-5" />
{{ $slot ?? '' }}
</button>
public function initiateEdit($id)
{
dd($id);
$this->selectedModel = $this->model::find($id);
}

Better solution instead of $wire.set to pass computed Alpine value for livewire

I am new in Alpine / Livewire. This tag script works well expect one thing: the form is sending continiusly query to the server. Is better way to pass the form data for livewire?
<div class="col-span-6 my-2" x-data="{tags: [], newTag: ''}" >
<x-jet-input id="tags"
type="text"
wire:model="tags"
:value="$wire.set('tags','JSON.stringify(tags)')"
class="mt-1 block w-full hidden"
/>
<div class=" w-full mx-auto ">
<div class="tags-input border-gray-300 shadow-sm focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
<template x-for="tag in tags" :key="tag">
<span class="tags-input-tag">
<span x-text="tag"></span>
<button type="button" class="tags-input-remove" #click="tags = tags.filter(i => i !== tag)">
×
</button>
</span>
</template>
<input class="tags-input-text w-full" placeholder="{{__('Add music tags eg.') }} Pop Trap Live..."
#keydown.enter.prevent="if (newTag.trim() !== '') tags.push(newTag.trim()); newTag = ''"
#keydown.space.prevent="if (newTag.trim() !== '') tags.push(newTag.trim()); newTag = ''"
#keydown.backspace="if (newTag.trim() === '') tags.pop()"
x-model="newTag"
/>
</div>
<x-jet-input-error for="tags" class="mt-2" />
<x-slot name="actions">
<x-jet-action-message class="mr-3" on="saved">
{{ __('Saved.') }}
</x-jet-action-message>
<x-jet-button
>
{{ __('Save') }}
</x-jet-button>
</x-slot>
For everyone who has problem with $wire.set:
I find the solution and is not in documentation.
$wire.set need third parameter true to skip watch function and it won't send data in the background if no need
$wire.set('param','value',true)

Custom validation on radio buttons if not selected | Tailwind

How to validate by showing a red ring around the radio button and make text red. Currently I am just showing a validation popup message. See image for a better idea.
Radio component
<input type="radio" {!! $attributes->class(['border-gray-300 text-gray-600 shadow-sm focus:border-gray-300 focus:ring focus:ring-gray-200 focus:ring-opacity-50', 'border-red-500 text-red-500' => $errors->has($attributes->get('name'))]) !!} />
Livewire view snippet
<div class="space-y-5">
#foreach ($ticket_types as $ticket_type)
<div>
<div class="relative flex items-start">
<div class="absolute flex items-center h-5">
<x-radio-button wire:model="ticket_type" #click="isQuestion = false" id="{{ $ticket_type->id }}" aria-describedby="{{ $ticket_type->id }}_description" value="{{ $ticket_type->id }}" class="h-4 w-4 transition duration-150 ease-in-out" />
</div>
<div class="pl-7 text-sm leading-5">
<x-jet-label for="{{ $ticket_type->id }}_title">
{{ $ticket_type->title }}
</x-jet-label>
<p id="{{ $ticket_type->id }}_description" class="text-gray-500">
{{ $ticket_type->description }}
</p>
</div>
</div>
</div>
#endforeach
</div>
<x-input-error for="ticket_type" />
Current look and feel
What I want to achieve (ignore the checkbox part)
You can conditionally include classes on components. So you could do something like:
<input type="radio"
{!! $attributes->class([
// these styles are applied by default
'border-gray-300 text-gray-600 shadow-sm focus:border-gray-300 focus:ring focus:ring-gray-200 focus:ring-opacity-50',
// these are applied if the name of the component is found in the error bag
// meaning there was an error
'border-red-500 text-red-500' => $errors->has($attributes->get('name'))
])
!!} />

How to prevent using a parameter when before clicked in Livewire

This code is a part of the View file connected with the Livewire component.
How to prevent using a parameter when before a button clicked?
View
...
#foreach ($babies as $baby)
...
<div
class="flex justify-between w-11-12 py-1 mb-1 ml-2 leading-6 text-sm font-medium ext-left text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-blue-800 focus:outline-none">
<button wire:click="setAte({{ $baby, $ate = 0 }})"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-ring-600 {{ $baby['ate'] == 0 ? "bg-blue-500" : "bg-red-500" }}">
S</button>
<button wire:click="setAte({{ $baby, $ate = 1 }})"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 1 ? "bg-blue-500" : "bg-red-500"}}">
M</button>
<button wire:click="setAte({{ $baby, $ate = 2}})"
class="flex w-1-3 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 2 ? "bg-blue-500" : "bg-red-500" }}">
L</button>
<div>{{ $baby['ate'] }}</div> {{-- <---check code --}}
</div>
#endforeach
...
Component
public function setAte($baby, $ate)
{
$baby['ate'] = $ate;
$selectedBaby = Baby::find($baby['id']);
$selectedBaby->save();
}
Error
Illuminate\Contracts\Container\BindingResolutionException
Unable to resolve dependency [Parameter #1 [ $ate ]] in class App\Http\Livewire\Classroom\BabyStatus
Solution 1
//Component
public $baby;
protected $rules = [
'baby.ate' => 'required|int|min:0|max:2'
];
public function updateAte($ate)
{
$this->baby->ate = $ate;
$this->baby->save();
}
//View
<button wire:model="baby" wire:click="updateAte(0)"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-ring-600 {{ $baby['ate'] == 0 ? "bg-blue-500" : "bg-red-500"}}">S</button>
<button wire:model="baby" wire:click="updateAte(1)"
class="flex w-1-3 mr-1 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 1 ? "bg-blue-500" : "bg-red-500"}}">M</button>
<button wire:model="baby" wire:click="updateAte(2)"
class="flex w-1-3 px-2 text-xs font-medium text-center text-white uppercase transition rounded shadow ripple hover:shadow-lg hover:bg-pink-800 focus:ring-pink-600 {{ $baby['ate'] == 2 ? "bg-blue-500" : "bg-red-500" }}">L</button>
That's all, thank you #Unflux.
I would be inclined to refactor what you have and make each baby a separate livewire component.
App\Http\Livewire\Baby.php
class Baby extends Component
{
// your instance of a baby
public $baby;
// required to allow updating of the baby properties
protected $rules = [
'baby.ate' => 'required|int|min:0|max:2'
];
public function render()
{
return view('livewire.baby');
}
// you can set the value of properties here if you want
public function mount()
{
// for example:
//$this->baby->ate = -100;
}
// when the value of ate is updated from the view
// update the baby model
public function updatedBaby()
{
$this->baby->save();
}
}
resoures\views\livewire\baby.blade.php
<div class="p-4 m-4">
<h4>Baby Component - ate: {{ $baby->ate }}</h4>
<div class="flex justify-between p-4 m-4">
<button wire:click="$set('baby.ate', 0)"
class="text-white px-2 rounded {{ $baby->ate === 0 ? "bg-blue-500" : "bg-red-500" }}">S
</button>
<button wire:click="$set('baby.ate', 1)"
class="text-white px-2 rounded {{ $baby->ate === 1 ? "bg-blue-500" : "bg-red-500" }}">M
</button>
<button wire:click="$set('baby.ate', 2)"
class="text-white px-2 rounded {{ $baby->ate === 2 ? "bg-blue-500" : "bg-red-500" }}">L
</button>
</div>
</div>
Note: The use of === in the above. Prevents null or similar values being incorrectly determined as equal to 0.
Then in your view:
#foreach($babies as $baby)
#livewire("baby", ["baby" => $baby]) // render your single baby component
#endforeach

Can't access component method inside my blade file

I am trying to access a method inside my blade file, with #click but I am getting an error
signup-modal.vue
<template>
<div>
<div v-if="modal" class="animated fadeIn fixed z-50 pin overflow-auto bg-black flex">
<div class="animated fadeInUp fixed shadow-inner max-w-md md:relative pin-b pin-x align-top m-auto justify-end md:justify-center p-8 bg-white md:rounded w-full md:h-auto md:shadow flex flex-col">
<p class="text-xl leading-normal mb-8 text-center">
{{ __("Sign up to name to start socializing") }}
</p>
<div class="justify-center">
<form action="/auth/register" method="post">
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Name" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Email" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Password" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="flex items-center justify-end">
<button class="bg-teal hover:bg-teal-dark text-white font-bold py-2 px-4 rounded" type="button">
{{ __("Sign up") }}
</button>
</div>
</form>
</div>
<span #click="toggleModal" class="absolute pin-t pin-r pt-4 px-4">
<svg class="h-6 w-6 text-grey hover:text-grey-darkest" role="button" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><title>Close</title><path d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/></svg>
</span>
</div>
</div>
</div>
</template>
<script>
export default {
data: function()
{
return {
modal: false
}
},
methods: {
toggleModal: function() {
console.log("djdjd")
//this.modal = !this.modal
}
}
}
</script>
app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
Vue.component('signup-modal', require('./components/signup-modal.vue'));
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app'
});
My blade file:
<div id="app">
<button class="bg-blue w-full rounded-full text-white py-2 mb-2" #click="toggleModal">
{{ __("Sign up") }}
</button>
</div>
<div>
<signup-modal></signup-modal>
</div>
</div>
As you can see in my blade file I am trying to access my components method toggleModal but I am getting an error:
app.js:36520 [Vue warn]: Property or method "toggleModal" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
(found in <Root>)
warn # app.js:36520
warnNonPresent # app.js:37826
has # app.js:37859
(anonymous) # VM374:3
Vue._render # app.js:40471
updateComponent # app.js:38715
get # app.js:39069
Watcher # app.js:39058
mountComponent # app.js:38722
Vue.$mount # app.js:44467
Vue.$mount # app.js:46866
Vue._init # app.js:40567
Vue # app.js:40656
(anonymous) # app.js:13896
__webpack_require__ # app.js:20
(anonymous) # app.js:13869
__webpack_require__ # app.js:20
(anonymous) # app.js:63
(anonymous) # app.js:66
app.js:36520 [Vue warn]: Invalid handler for event "click": got undefined
Why is this and how can I fix it?
To achieve what I wanted to do, I went the event-based way. For example, in my component, I added the method mounted, and added the following:
mounted()
{
eventHub.$on('signup-click', this.toggleModal)
}
And my main Vue method I added a simple event emitter method like so:
const app = new Vue({
el: '#app',
methods: {
generateEvent: (event) => {
eventHub.$emit(event);
}
}
});
And then in my blade file, I simple called that method like so:
<button class="bg-blue w-full rounded-full text-white py-2 mb-2" #click="generateEvent('signup-click')">
{{ __("Sign up") }}
</button>
Which simple emits the event, so my component listens to it, then calls that child method.

Resources