Laravel Livewire using flatpickr - laravel

Im trying to make us of the flatpickr event onMonthChange but using via a Livewire method.
I am using the answer from this - How to make flatpickr datepicker reactive in livewire / alpinejs app?
But having trouble knowing how to trigger the onMonthChange js event then running livewire method.
views/components/flatpickr.blade.php
#props(['options'])
<div wire:ignore>
<input
x-data="{value: #entangle($attributes->wire('model')), instance: undefined}"
x-init="() => {
$watch('value', value => instance.setDate(value, true));
instance = flatpickr($refs.input, {{ json_encode((object)$options) }});
}"
x-ref="input"
x-bind:value="value"
type="text"
{{ $attributes->merge(['class' => 'form-input w-full rounded-md shadow-sm']) }}
/>
</div>
views/livewire/booking-search.blade.php
<div class="col-span-6 sm:col-span-3">
<label for="datePicker" class="block text-sm text-gray-700 font-semibold">Select Date</label>
<x-flatpickr id="flatpickr_operation_date" wire:model="selectedDate" :options="$options"/>
</div>
app/Http/Livewire/BookingSearch.php
class BookingSearch extends Component
{
public $selectedDate;
public $selectedMonth
public $options = [
'minDate' => 'today',
'maxDate' => "2022-05-31",
'inline' => true,
'monthSelectorType' => 'static',
'dateFormat' => 'd-m-Y',
'enableTime' => false,
'altFormat' => 'j F Y',
'altInput' => true,
];
public function updatedSelectedMonth() {
dd('foo');
}
So im trying to get updatedSelectedMonth to run when the month is changed but because its not a input it self, just not sure how to get livewire to fire on the change.
Sorry JS isnt my strongest

Related

My laravel livewire create form keeps giving me errors

LONG POST WARNING
why isn't my form to create a new user not working? im using laravel 9 and livewire. This is my code:
this is the button from where i show the model to create a form:
<div class="py-4 space-y-4">
<div class="flex justify-between px-2">
<div class="w-1/4">
<x-jet-input placeholder="search will go here"/>
</div>
<div>
<x-jet-button wire:click="create">New Skill</x-jet-button>
</div>
</div>
</div>
This is the model that shows the form. this model is also used to edit a skill as per Caleb the livewire creator:
<form wire:submit.prevent="save">
<x-jet-dialog-modal wire:model.defer="showEditModal">
<x-slot name="title">Edit Skill</x-slot>
<x-slot name="content">
<div class="col-span-6 sm:col-span-4">
<x-jet-label for="name" value="{{ __('Skill name') }}" />
<select wire:model="editing.name"
id="name"
type="text"
class="mt-1 block w-full border-gray-300
focus:border-indigo-300 focus:ring
focus:ring-indigo-200 focus:ring-opacity-50
rounded-md shadow-sm">
#foreach(\App\Models\Skill::LANGUAGES as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
#endforeach
</select>
<x-jet-input-error for="editing.name" class="mt-2" />
<x-jet-label for="years" value="{{ __('Years of experience') }}" class="mt-4"/>
<x-jet-input wire:model="editing.years" id="years" type="number"
min="{{\App\Models\Skill::MIN_YEARS_OF_EXPERIENCE}}"
max="{{\App\Models\Skill::MAX_YEARS_OF_EXPERIENCE}}"
class="mt-1 block w-full"
placeholder="Years of experience"/>
<x-jet-input-error for="editing.years" class="mt-2" />
</div>
</x-slot>
<x-slot name="footer">
<x-jet-secondary-button wire:click="$set('showEditModal', false)" class="mr-2">Cancel</x-jet-secondary-button>
<x-jet-button type="submit">Save</x-jet-button>
</x-slot>
</x-jet-dialog-modal>
</form>
And this is my livewire component:
<?php
namespace App\Http\Livewire;
use App\Models\Skill;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class Skills extends Component
{
public $name ='';
public $showEditModal = false;
public Skill $editing;
public function rules()
{
return [
'editing.name' => 'required|in:'.collect(Skill::LANGUAGES)->keys()->implode(','),
'editing.years' => 'required|numeric|between:' . Skill::MIN_YEARS_OF_EXPERIENCE . ',' . Skill::MAX_YEARS_OF_EXPERIENCE,
];
}
public function render()
{
return view('livewire.skills', [
'skills' => Skill::where('user_id', auth()->id())->get(),
]);
}
public function mount(){
$this->editing = $this->makeBlankSkill();
}
public function makeBlankSkill(){
return Skill::make([
'name' => 'javascript',
'user_id' => auth()->user()->id,
]);
}
public function create(){
if ($this->editing->getKey()) $this->editing = $this->makeBlankSkill();
$this->showEditModal = true;
}
public function edit(Skill $skill) {
if ($this->editing->isNot($skill)) $this->editing = $skill;
$this->showEditModal = true;
}
public function save()
{
$this->validate();
$this->editing->save();
$this->showEditModal = false;
}
}
I keep getting SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value and i dont know why.
This is my modal:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Skill extends Model
{
use HasFactory;
const DEFAULT_OPTION = 'Please select a skill';
const LANGUAGES = [
'javascript' => 'JavaScript',
'php' => 'PHP',
'python' => 'Python',
'java' => 'Java',
'c#' => 'C#',
'c++' => 'C++',
'ruby' => 'Ruby',
'swift' => 'Swift',
'typescript' => 'TypeScript',
'rust' => 'Rust',
'go' => 'Go',
'kotlin' => 'Kotlin',
'scala' => 'Scala',
'dart' => 'Dart',
'r' => 'R',
'perl' => 'Perl',
'elixir' => 'Elixir',
'clojure' => 'Clojure',
'haskell' => 'Haskell',
'erlang' => 'Erlang',
'lisp' => 'Lisp',
'sql' => 'SQL',
'bash' => 'Bash',
'laravel' => 'Laravel',
'symfony' => 'Symfony',
'codeigniter' => 'CodeIgniter',
'yii' => 'Yii',
'zend' => 'Zend',
'cakephp' => 'CakePHP',
'fuelphp' => 'FuelPHP',
'slim' => 'Slim',
'lumen' => 'Lumen',
'phalcon' => 'Phalcon',
'silex' => 'Silex',
'express' => 'Express',
'koa' => 'Koa',
'hapi' => 'Hapi',
'meteor' => 'Meteor',
'angular' => 'Angular',
'ember' => 'Ember',
'react' => 'React',
'vue' => 'Vue',
'backbone' => 'Backbone',
'd3' => 'D3',
'threejs' => 'Three.js',
];
const MIN_YEARS_OF_EXPERIENCE = 1;
const MAX_YEARS_OF_EXPERIENCE = 50;
protected $fillable = [
'name', 'user_id', 'years'
];
public function user()
{
return $this->belongsTo(User::class);
}
}
Any help is greatly appriceated
I've done all there is to do.At least i hope. I've added the
$illable
array ive set the
'user_id' => auth()->user()->id,
Not sure what else im missing
public function save()
{
$this->validate();
$user = auth()->user();
$this->editing->user_id = $user->id;
$this->editing->save();
$this->showEditModal = false;
}
This was the answer for me
If user_id is null when creating a new Skill, this means there is no authenticated user. You can simply check by doing dd(auth()->id()). If you're logged in, this will return the primary key for your authentication model. If this is empty, you're simply not authenticated, and so you must first log in.
In the case your user_id is actually set, but it isn't arriving in your database upon saving, you'll have to check if the property user_id is correctly set on the Skill model's protected $fillable property.
If you dd($this->editing) right after mount, you can check the attributes of the model, and if the user_id is set, you know the error happens when saving to the database.
As it turns out, Livewire won't hydrate newly set properties on models. This is because Livewire "rehydrates" the models by simply re-fetching them from the database. This can be solved defining a rules property as shown here, directly relating to the model properties. This would ensure Livewire keeps the state of the updated properties.

Livewire quantity input field not update dynamically when change value

I've purchased pos software which is not updated the quantity input field when changed into the checkout page it's working with a button. I want to change form submit button quantity input to dynamic input field with cart total, not with a hard-coded button.
Screenshot of this problem
Blade Code
<form wire:submit.prevent="updateQuantity('{{ $cart_item->rowId }}', '{{ $cart_item->id }}')">
<div class="input-group">
<input wire:model.lazy="quantity.{{ $cart_item->id }}" style="min-width: 40px;max-width: 90px;" type="number" class="form-control" value="{{ $cart_item->qty }}" min="1">
<div class="input-group-append">
<button type="submit" class="btn btn-primary">
<i class="bi bi-check"></i>
</button>
</div>
</div>
Update function
public function updateQuantity($row_id, $product_id) {
if ($this->check_quantity[$product_id] < $this->quantity[$product_id]) {
session()->flash('message', 'The requested quantity is not available in stock.');
return;
}
Cart::instance($this->cart_instance)->update($row_id, $this->quantity[$product_id]);
$cart_item = Cart::instance($this->cart_instance)->get($row_id);
Cart::instance($this->cart_instance)->update($row_id, [
'options' => [
'sub_total' => $cart_item->price * $cart_item->qty,
'code' => $cart_item->options->code,
'stock' => $cart_item->options->stock,
'unit' => $cart_item->options->unit,
'product_tax' => $cart_item->options->product_tax,
'unit_price' => $cart_item->options->unit_price,
'product_discount' => $cart_item->options->product_discount,
'product_discount_type' => $cart_item->options->product_discount_type,
]
]);
}

Uncaught (in promise) TypeError: initialData is null - my components are wrapped in a single div but still getting the error

I am getting an initial data is null error. This has been talked about github forum, however, the answer was that the component was not wrapped in a single div. My components are. So I am still getting:
Uncaught (in promise) TypeError: initialData is null
I have a simple button that runs a function when clicked
which is produced by this code:
<div class="mx-0 col-span-1 block font-medium text-sm text-gray-700 mb-0">
<x-green-button-sm class="px-0 mx-0" title="Add a New person to the family." wire:click="createChild">
<h3 class="my-0 text-xss">Add Child</h3>
</x-green-button-sm>
#livewire('admin.shared.edit-add-child', ['showEditAddChildModal' => $showEditAddChildModal,
'editadd' => 'add', 'userid' => $user->id, 'registrantOrAdmin' => $registrantOrAdmin])
</div>
Which calls this function in the component
public function createChild(){
$this->showEditAddChildModal = true;
}
And notice that the livewire component above is passed the value of $showEditAddChildModal
The beginning of the admin.shared.edit-add-child blade component is:
<div>
<form wire:submit.prevent="save">
<x-modal.dialog wire:model="showEditAddChildModal">
......
.....
</div> // the blade component is contained in a single div as required
so the effort is to make the model visible obviously. The admin.shared.edit-add-child blade blade makes reference to models (public properties) like this
wire:model.debounce.500ms="editChild.firstname"
the EditAddChild.php component is set up like this:
<?php
namespace App\Http\Livewire\Admin\Shared;
use App\Models\Person;
use Livewire\Component;
class EditAddChild extends Component
{
public $showEditAddChildModal = false;
//(if i set the above true, the modal does show up.)
public $userid;
public $txtmsgp;
public $fullname;
public $registrantOrAdmin;
public $editadd;
public $editChild;
// (I started with public Person $editChild but the system balked at //initializing a typed variable in the mount() function)
public $dateOfBirth;
Below, note that the $this->editadd variable is passed in the #livewire call seen above. The mount() function in the EditAddChild.php component is:
public function mount(){
if($this->editadd == 'add')
$this->editChild = $this->addNewChild();
}
addNewChild() is:
public function addNewChild()
{
return Person::make(['added_by' => auth()->user()->id,
'updated_by' => null,
'family_type' => 'child',
'firstname' => '',
'lastname' => '',
'pronouns' => 'u',
'sex' => 'u',
'dob' => now(),
'age_today' => 0,
'mobile_phone' => null,
'receive_texts' => 'u',
'email' => '',
'allow_emails' => 'u',
'member' => 'u',
'allow_photos' => 'u',
'show' => 0,
]);
}
when i click on the add child button to change the x-show variable to true, the modal does not show and the console reports this:
My apologies, but I thought I would list the entire modal coponent as well. There are two parts [dialog.blade.php] :
#props(['id' => null, 'maxWidth' => null])
<x-modal :id="$id" :maxWidth="$maxWidth" {{ $attributes }}>
<div class="px-6 py-4">
<div class="text-lg">
{{ $title }}
</div>
<div class="mt-4">
{{ $content }}
</div>
</div>
<div class="px-6 py-4 bg-gray-100 text-right">
{{ $footer }}
</div>
</x-modal>
the second part being [modal.bade.php]:
#props(['id', 'maxWidth'])
#php
$id = $id ?? md5($attributes->wire('model'));
$maxWidth = [
'sm' => 'sm:max-w-sm',
'md' => 'sm:max-w-md',
'lg' => 'sm:max-w-lg',
'xl' => 'sm:max-w-xl',
'2xl' => 'sm:max-w-2xl',
'3xl' => 'sm:max-w-3xl',
'4xl' => 'sm:max-w-4xl',
'5xl' => 'sm:max-w-5xl',
'6xl' => 'sm:max-w-6xl',
'7xl' => 'sm:max-w-7xl',
][$maxWidth ?? '3xl'];
#endphp
<div
x-data="{
show: #entangle($attributes->wire('model')).defer,
focusables() {
// All focusable element types...
let selector = 'a, button, input, textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
return [...$el.querySelectorAll(selector)]
// All non-disabled elements...
.filter(el => ! el.hasAttribute('disabled'))
},
firstFocusable() { return this.focusables()[0] },
lastFocusable() { return this.focusables().slice(-1)[0] },
nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() },
prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() },
nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) },
prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 },
}"
x-init="$watch('show', value => {
if (value) {
document.body.classList.add('overflow-y-hidden');
} else {
document.body.classList.remove('overflow-y-hidden');
}
})"
x-on:close.stop="show = false"
x-on:keydown.escape.window="show = false"
x-on:keydown.tab.prevent="$event.shiftKey || nextFocusable().focus()"
x-on:keydown.shift.tab.prevent="prevFocusable().focus()"
x-show="show"
id="{{ $id }}"
class="overflow-auto jetstream-modal fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50"
style="display: none;"
>
<div x-show="show" class="fixed inset-0 transform transition-all" x-on:click="show = false"
x-transition:enter="ease-out duration-3000"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-3000"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<div x-show="show" class="mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
{{ $slot }}
</div>
</div>
Please check in here
#livewire('admin.shared.edit-add-child', ['showEditChildModal' => $showEditAddChildModal,
'editadd' => 'add', 'userid' => $user->id, 'registrantOrAdmin' => $registrantOrAdmin])
precisely at "'showEditChildModal' => $showEditAddChildModal" part. You're binding the parent property ($showEditAddChildModal) to the child ('showEditChildModal'), but in the child component that property doesn't exist, instead you have declared the property as next:
public $showEditAddChildModal = false;
It's a typo of you should fix it???

production.ERROR: InvalidArgumentException: Data missing in Laravel

I am working on a project in Laravel-5.8. I have this in my model:
Model:
protected $fillable = [
'id',
'email',
'hire_date',
'first_name',
'other_name',
'last_name',
'date_of_birth',
];
protected $dates = [
'date_of_birth',
'hire_date',
];
public function setDateOfBirthAttribute($value)
{
$this->attributes['date_of_birth'] = Carbon::createFromFormat('d-m-Y', $value);
}
public function setHireDateAttribute($value)
{
$this->attributes['hire_date'] = Carbon::createFromFormat('d-m-Y', $value);
}
Then this is my controller.
Controller:
$arr = [
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'hire_date' => $request->hire_date,
'date_of_birth' => $request->date_of_birth,
'other_name' => $request->other_name,
];
$employee = HrEmployee::create($arr);
I use JQuery datepicker:
< script type = "text/javascript" >
$(function() {
$('.birthDate').datepicker({
dateFormat: 'dd-mm-yy',
changeMonth: true,
changeYear: true,
maxDate: -1,
showAnim: 'slideDown',
duration: 'fast',
});
}); <
/script>
<div class="col-12 col-sm-4">
<div class="form-group">
<label class="control-label"> Date of Birth:</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="far fa-calendar-alt"></i></span>
</div>
<input type="text" placeholder="dd/mm/yyyy" readonly autocomplete="off" name="date_of_birth" value="{{ old(" date_of_birth} ") }}" class="form-control birthDate">
</div>
</div>
<!-- /.form-group -->
</div>
When I submitted the form, I got this error:
[2021-02-12 12:50:07] production.ERROR: InvalidArgumentException: Data missing in /var/www/html/peopleedgeapp/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php:623
Stack trace:
#0 /var/www/html/myapp/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php(645): Carbon\Carbon::rawCreateFromFormat('d-m-Y', NULL, NULL)
#1 /var/www/html/myapp/app/Models/Hr/HrEmployee.php(156): Carbon\Carbon::createFromFormat('d-m-Y', NULL)
#2 /var/www/html/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(615): App\Models\Hr\HrEmployee->setDateOfBirthAttribute(NULL)
#3 /var/www/html/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(569): Illuminate\Database\Eloquent\Model->setMutatedAttributeValue('date_of_birth', NULL)
#4 /var/www/html/myapp/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(329): Illuminate\Database\Eloquent\Model->setAttribute('date_of_birth', NULL)
Where did I get it wrong? The same error occur for hire_date.
How do I get this resolved?
Thanks
Hard to say what's exactly wrong but for sure there is a problem here:
value="{{ old(" date_of_birth} ") }}"
It should be rather:
value="{{ old('date_of_birth') }}"
First of all set attribute methods are not used for guarded fields.
They have completely different perpouse.
Secondary, according to your error log somehow your setters were triggered with NULL passing instead of parameters, where parameters are required which is also wrong.
So where your setters triggered that is the question I think.

How to get proper data when using blade components and alpinejs?

I'm new in components and alpine in laravel. I have data from controller $positions.
$positions = [
['id' => 1, 'content' => 'king'],
['id' => 2, 'content' => 'lord']
];
When I pass it to laravel blade. here is my code
<div class="row">
<div class="col">
#foreach($list as $key => $position)
<x-list :position="$position"/>
#endforeach
</div>
</div>
I have component name it <x-list/> with a prop position, and here is the code of my x-list component
<div class="red w-60 mb-1">
<div x-data="positionData()" class="relative">
<button #click="submit()" class="p-2">Submit</button>
</div>
</div>
<script>;
var position = #json($position);
function positionData() {
return {
submit() {
console.log(position);
},
};
}
</script>
It is just very simple code but when I click the submit button, the data I get is the last position
from the list ['id' => 2, 'content' => 'lord'], even I click position 1 the data I get is still position 2 data. I don't know what happen now. I try to search it in google to fix it but I can't find the right answer on this.
I think the issue in this case is that the positionData function is being overwritten on each iteration of x-list (since each of the components is creating a new window.positionData function).
To solve it you could do:
<div class="red w-60 mb-1">
<div x-data="positionData(#json($position))" class="relative">
<button #click="submit()" class="p-2">Submit</button>
</div>
</div>
<script>;
function positionData(position) {
return {
submit() {
console.log(position);
},
};
}
</script>
Specifically, you should probably move the <script></script> out of the x-list component so that it doesn't get re-created for each component (it should only be added to the page once).

Resources