F
Filament‱15mo ago
Chriis

Type of TextInput numeric()

Hi, I can't figure out what's the the type coming out of a numeric TextInput and have a hard time to test it ... Someone know ?
105 Replies
DrByte
DrByte‱15mo ago
Can you give an example of what you're trying to do? Do you mean you're trying to do custom validation? a custom rule? What are you doing with the state you've retrieved from the component?
awcodes
awcodes‱15mo ago
I usually use the lifecycle method on my create or edit record class to dd the form state to see what data is getting output by the form. Both classes have a public method where you can dd $this->form->getState() to see the form values after validation.
Chriis
ChriisOP‱15mo ago
This is the TextInput, what type of value this input store ? A string, an int, ... ?
No description
Chriis
ChriisOP‱15mo ago
Ok, good to know thx Ok so after some research its seems like its impossible to have an integer in an input. It always comes out as a string 😩
toeknee
toeknee‱15mo ago
That's how livewire works just cast it? (int)
Chriis
ChriisOP‱15mo ago
Yes but casting make it an int when I save the form data However I'm in a Wizard 😑 So if I understand right, I will always have a string in my next step ?
toeknee
toeknee‱15mo ago
Yep
Chriis
ChriisOP‱15mo ago
Great ... I can cancel my entire project 😅
toeknee
toeknee‱15mo ago
ahaha why?
Chriis
ChriisOP‱15mo ago
Well I really need an int for placing it in a ->defaultItems of a repeater If I don't have that the creation of my resource make no sense
toeknee
toeknee‱15mo ago
just cast it when getting the value? (int) $get('myValue') ?
Chriis
ChriisOP‱15mo ago
Ok, I think I don't understand casting 😅 What is this '(int)' ?
toeknee
toeknee‱15mo ago
That's standard php casting, there is also model casting which does the same thing but on the model level it's like php 101 https://www.php.net/manual/en/language.types.type-juggling.php
Chriis
ChriisOP‱15mo ago
Well I understand Model casting but I didn't know about this one, I'm going to look a that
toeknee
toeknee‱15mo ago
It's like the first thing you learn when learning php...
Chriis
ChriisOP‱15mo ago
Ah, well after multiple years and courses on PHP ... I pretty sure I have never seen that
Chriis
ChriisOP‱15mo ago
Like that right ?
No description
Dennis Koch
Dennis Koch‱15mo ago
Yes
Chriis
ChriisOP‱15mo ago
Still doesn't work
Chriis
ChriisOP‱15mo ago
No description
Chriis
ChriisOP‱15mo ago
Here I should have 4 repeater block but nothing
Chriis
ChriisOP‱15mo ago
No description
Chriis
ChriisOP‱15mo ago
No description
Dennis Koch
Dennis Koch‱15mo ago
Is the TextInput reactive?
Chriis
ChriisOP‱15mo ago
Nope It should be ?
Dennis Koch
Dennis Koch‱15mo ago
How do you expect a change then? Yes. I wouldn’t mention it otherwise. I think it’s called live() now Did you check the Advanced Forms section?
Chriis
ChriisOP‱15mo ago
I need a live() only to $get a value ? Just to precise is between 2 Wizard steps
Dan Harrin
Dan Harrin‱15mo ago
the default items load when the form is loaded. not when after the field is updated you need to add an afterStateUpdated() and $set the repeater with the correct number of items
Chriis
ChriisOP‱15mo ago
Ah ok But how can I $set a certain method on the repeater (defaultItems in this case) ? I haven't seen it in the doc
toeknee
toeknee‱15mo ago
Run set with empty values in an array
Dennis Koch
Dennis Koch‱15mo ago
You don't "set a method". You can only set a form state You need live() to notice a change of the value. Because otherwise it's not updated until you hit submit. But as Dan stated, this isn't the issue here.
Chriis
ChriisOP‱15mo ago
uuuh ok
Chriis
ChriisOP‱15mo ago
I'm lost honestly.
No description
toeknee
toeknee‱15mo ago
I think a simple $set with the default schema. No the days won’t work, you need to pass in the data schema. So: $set(‘tasks’, [[‘task’ => ‘’],[‘task’ => ‘’]]) Building a loop for the array creation based off the days.
Chriis
ChriisOP‱15mo ago
Its doesnt work
toeknee
toeknee‱15mo ago
Provide your code.
Chriis
ChriisOP‱15mo ago
I don't understand how the 'days' repeater can have a new block created by adding a new task to the sub-repeater 'tasks'
toeknee
toeknee‱15mo ago
Provide your code.
Chriis
ChriisOP‱15mo ago
The code is what you said
toeknee
toeknee‱15mo ago
Provide your code. i.e. the entire code of your wizard.
Chriis
ChriisOP‱15mo ago
No description
toeknee
toeknee‱15mo ago
Stop providing screenshots as per #✅┊rules provide the code
Chriis
ChriisOP‱15mo ago
class CreateSheet extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;

protected static string $resource = SheetResource::class;

protected function getSteps(): array
{
return [
Step::make('Informations générales')
->schema([
SheetResource::getTitleFormField(),
SheetResource::getCodeFormField(),
SheetResource::getTrainersFormField(),
SheetResource::getTargetAudienceFormFieldset(),
SheetResource::getDurationFormFieldset(),
SheetResource::getObjectivesFormSection(),
SheetResource::getPrerequisitesFormSection(),
SheetResource::getConditionsFormSection(),
])->columns(2),
Step::make('Programme')
->schema([
SheetResource::getTestFormField(),
SheetResource::getScheduleFormRepeater(),
]),
Step::make('Compétences')
->schema([]),
Step::make("Grille d'Ă©valuation")
->schema([])
];
}
}
class CreateSheet extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;

protected static string $resource = SheetResource::class;

protected function getSteps(): array
{
return [
Step::make('Informations générales')
->schema([
SheetResource::getTitleFormField(),
SheetResource::getCodeFormField(),
SheetResource::getTrainersFormField(),
SheetResource::getTargetAudienceFormFieldset(),
SheetResource::getDurationFormFieldset(),
SheetResource::getObjectivesFormSection(),
SheetResource::getPrerequisitesFormSection(),
SheetResource::getConditionsFormSection(),
])->columns(2),
Step::make('Programme')
->schema([
SheetResource::getTestFormField(),
SheetResource::getScheduleFormRepeater(),
]),
Step::make('Compétences')
->schema([]),
Step::make("Grille d'Ă©valuation")
->schema([])
];
}
}
In SheetResource.php
public static function getDurationFormFieldset(): Fieldset
{
return Fieldset::make('Durée')
->schema([
TextInput::make('hours')
->label('Heure(s)')
->suffix('h')
->numeric()
->required(),
TextInput::make('days')
->label('Jour(s)')
->suffix('j')
->numeric()
->live()
->afterStateUpdated(function (Forms\Get $get, Forms\Set $set){
$set('tasks', [['task' => ''],['task' => '']]);
})
->required()
]);
}

public static function getScheduleFormRepeater()
{
return Repeater::make('schedule')
->addable(false)
->reorderable(false)
->deletable(false)
->label('Programme')
->collapsed()
->defaultItems(function (Forms\Get $get){
return (int) $get('days');
})
->schema([
Repeater::make('tasks')
->label('Liste des tĂąches')
->defaultItems(1)
->simple(
TextInput::make('task')
)
]);
}
public static function getDurationFormFieldset(): Fieldset
{
return Fieldset::make('Durée')
->schema([
TextInput::make('hours')
->label('Heure(s)')
->suffix('h')
->numeric()
->required(),
TextInput::make('days')
->label('Jour(s)')
->suffix('j')
->numeric()
->live()
->afterStateUpdated(function (Forms\Get $get, Forms\Set $set){
$set('tasks', [['task' => ''],['task' => '']]);
})
->required()
]);
}

public static function getScheduleFormRepeater()
{
return Repeater::make('schedule')
->addable(false)
->reorderable(false)
->deletable(false)
->label('Programme')
->collapsed()
->defaultItems(function (Forms\Get $get){
return (int) $get('days');
})
->schema([
Repeater::make('tasks')
->label('Liste des tĂąches')
->defaultItems(1)
->simple(
TextInput::make('task')
)
]);
}
toeknee
toeknee‱15mo ago
This seem far to complicated, but you need to traverse to set the tasks
Chriis
ChriisOP‱15mo ago
What do you mean by "traverse" ?
toeknee
toeknee‱15mo ago
public static function getDurationFormFieldset(): Fieldset
{
return Fieldset::make('Durée')
->schema([
TextInput::make('hours')
->label('Heure(s)')
->suffix('h')
->numeric()
->required(),
TextInput::make('days')
->label('Jour(s)')
->suffix('j')
->numeric()
->live()
->afterStateUpdated(function (Forms\Get $get, Forms\Set $set, $state){
$days = (int) $state;
$original_items = $get('../schedule/tasks');
for ($i=0; $i <= ($days - count($original_items)); $i++) {
$original_items[] = [];
}
$set('../schedule/tasks', $original_items);
})
->required()
]);
}

public static function getScheduleFormRepeater()
{
return Repeater::make('schedule')
->addable(false)
->reorderable(false)
->deletable(false)
->label('Programme')
->collapsed()
->defaultItems(function (Forms\Get $get){
return (int) $get('days');
})
->schema([
Repeater::make('tasks')
->label('Liste des tĂąches')
->defaultItems(1)
->simple(
TextInput::make('task')
)
]);
}
public static function getDurationFormFieldset(): Fieldset
{
return Fieldset::make('Durée')
->schema([
TextInput::make('hours')
->label('Heure(s)')
->suffix('h')
->numeric()
->required(),
TextInput::make('days')
->label('Jour(s)')
->suffix('j')
->numeric()
->live()
->afterStateUpdated(function (Forms\Get $get, Forms\Set $set, $state){
$days = (int) $state;
$original_items = $get('../schedule/tasks');
for ($i=0; $i <= ($days - count($original_items)); $i++) {
$original_items[] = [];
}
$set('../schedule/tasks', $original_items);
})
->required()
]);
}

public static function getScheduleFormRepeater()
{
return Repeater::make('schedule')
->addable(false)
->reorderable(false)
->deletable(false)
->label('Programme')
->collapsed()
->defaultItems(function (Forms\Get $get){
return (int) $get('days');
})
->schema([
Repeater::make('tasks')
->label('Liste des tĂąches')
->defaultItems(1)
->simple(
TextInput::make('task')
)
]);
}
somehting along those lines Traverse so go through it with ../ because each repeater is it's own statepath. Quickest way to debug the correct depth you need to go to, add 1 item to the tasks. Then $original_items = $get('../schedule/tasks'); dd($original_items); If it is empty, you may need to remove../ or add it if memory serves me correctly
Chriis
ChriisOP‱15mo ago
No description
toeknee
toeknee‱15mo ago
Which show's it's not the correct path to the repeater
Chriis
ChriisOP‱15mo ago
Ah
toeknee
toeknee‱15mo ago
if it was correct then it would be fine. I tested the core here on a single form from a single text input tot update a simple repeater on the same element
Chriis
ChriisOP‱15mo ago
I can't manage to fix the issue I've tried to test the repeater path but nothing
toeknee
toeknee‱15mo ago
It's in a different step too
Chriis
ChriisOP‱15mo ago
yes, so ?
toeknee
toeknee‱15mo ago
You may need to jump out of the step, I can't remember exactly. But I suggest you install livewire chrome tools and inspect the data structure in the console to ensure you know where you are traversing too. The form is overly complex imho.
Chriis
ChriisOP‱15mo ago
Ok. Wdym by overly complex ? I didnt thought it would be so difficult to do such a thing, but I dont know how I can do in a different way xD
toeknee
toeknee‱15mo ago
Looking at the data structure I don't think you do. But you need to learn this stuff yourself too. I've provide the method that works on a standard form. You just need to work out the correct traversal path for your code to get to that repeater
Chriis
ChriisOP‱15mo ago
I think in the error the problem really come from the fact that 'days' is still a string
toeknee
toeknee‱15mo ago
It is not, I’ve told you what the error is Days is cast to int in the code.
Chriis
ChriisOP‱15mo ago
Yes, sorry ...
array:4 [
"data" => array:15 [
"record" => null
"data" => array:4 [
"test_days" => null
"schedule" => array:1 [
"2f02da1b-4c7b-48da-8ec2-184dee4138ab" => array:1 [
"tasks" => array:1 [
"7b4b687a-e6dc-4a63-b4f2-93a8dcc8bbb9" => array:1 [
"task" => array:1 [
"task" => null
]
]
]
]
]
"hours" => null
"days" => null
]
array:4 [
"data" => array:15 [
"record" => null
"data" => array:4 [
"test_days" => null
"schedule" => array:1 [
"2f02da1b-4c7b-48da-8ec2-184dee4138ab" => array:1 [
"tasks" => array:1 [
"7b4b687a-e6dc-4a63-b4f2-93a8dcc8bbb9" => array:1 [
"task" => array:1 [
"task" => null
]
]
]
]
]
"hours" => null
"days" => null
]
So this is the data tree and what's weird is that schedule is a the same level than days And when I $get with the path based on this tree its null 😑 Oh its probably because there is this sort of id between 'schedule' and 'tasks' Can you explain a bit more about that ? please
Dan Harrin
Dan Harrin‱15mo ago
i dont have the time right now, i do think there are plenty of examples online also there are many knowledgeable people here who also know what im talking about setting a field when another field is updated is quite common
Chriis
ChriisOP‱15mo ago
Ok no problem, but just is it possible to update the defaultItems with afterStateUpdated() ?
Dan Harrin
Dan Harrin‱15mo ago
defaultitems does not need to be used you $set the entire content of the repeater in afterstateupdated so you can add as many items as you want defaultitems is only relevant when the form is first loaded
Chriis
ChriisOP‱15mo ago
Ah ok I'm going to search how to do that thx
SirFat
SirFat‱15mo ago
I thought that was echo 'Hello World'; 🧐
toeknee
toeknee‱15mo ago
Hence 'Like' 🙂
Chriis
ChriisOP‱15mo ago
@toeknee So do you know why there is this a sort of uuid between the repeaters ? Which is probably stoping me to reach the value I want
toeknee
toeknee‱15mo ago
Yes, the uuid is the unique ID for the repeater element that livewire uses But that's just the array key It shouldn't affect your traversal Did you install livewire tools for chrome to view the data stack?
Chriis
ChriisOP‱15mo ago
Yes, I have this but there is absolutely nothing in it
No description
toeknee
toeknee‱15mo ago
Click the state icon
Chriis
ChriisOP‱15mo ago
I tried to 'select' something but it changed nothing, Idk if I'm that dumb or what 😅
Chriis
ChriisOP‱15mo ago
No description
toeknee
toeknee‱15mo ago
Then refresh the page and access the form
Chriis
ChriisOP‱15mo ago
still nothing
toeknee
toeknee‱15mo ago
And you open the console on the page wiht livewire?
Chriis
ChriisOP‱15mo ago
No description
toeknee
toeknee‱15mo ago
Strange working here click the red dot then click it again
Chriis
ChriisOP‱15mo ago
I've tried while recording (red dot) and without and its the same ofc after refreshing the page, accessing the form ... I must be cursed 😂
toeknee
toeknee‱15mo ago
Should look something like this, FYI it is all faker data 😄
No description
toeknee
toeknee‱15mo ago
Im am using Edge and the livewire extension... so maybe try that
Chriis
ChriisOP‱15mo ago
The problem must come from here
No description
toeknee
toeknee‱15mo ago
Ahh you have enabled production mode? change to local or dev
Chriis
ChriisOP‱15mo ago
I don't know if its related but APP_DEBUG is true and APP_ENV is local
toeknee
toeknee‱15mo ago
APP_ENV local should be good
Chriis
ChriisOP‱15mo ago
Nope its weird
Chriis
ChriisOP‱15mo ago
No description
toeknee
toeknee‱15mo ago
Ahh actually you are on V3. It might not work on V3 😐
Chriis
ChriisOP‱15mo ago
Yep its V3
toeknee
toeknee‱15mo ago
Sorry my bad, But the principle should be the same Traversal should be fine, although there could be some parent fetchers with v3 introduced. I just haven't used it too much And yep the dev tools doesn't work, we are waiting for caleb to release livewire/wiretap.
Chriis
ChriisOP‱15mo ago
Ok, too bad Honestly I don't know what to more than that ... except having a good old manual repeater 😅
toeknee
toeknee‱15mo ago
Can you provide the whole resource and model and I'll take a look.
Chriis
ChriisOP‱15mo ago
Yeah no problem, SheetResource
toeknee
toeknee‱15mo ago
What's your logic for writing so many functions for the repeaters?
Chriis
ChriisOP‱15mo ago
Because right now I'm only working on the CreateRecord (in another file) but when I would work on the edit form (i.e. SheetResource form) I don't have to duplicate the code
toeknee
toeknee‱15mo ago
but you just use ->form()
Chriis
ChriisOP‱15mo ago
Uh ? đŸ€”
toeknee
toeknee‱15mo ago
public static function form(Form $form): Form { return $form ->schema([ ]); } Is where you build the schema usually You have built ton's of functions which isn't too bad if you are heavily reusing the code but it's messy when it's a simple edit/create
Chriis
ChriisOP‱15mo ago
(last file) CreateSheet
<?php

namespace App\Filament\Resources\SheetResource\Pages;

use App\Filament\Resources\SheetResource;
use Faker\Provider\Text;
use Filament\Actions;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Wizard\Step;
use Filament\Resources\Pages\CreateRecord;
use Symfony\Component\Console\Input\Input;

class CreateSheet extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;

protected static string $resource = SheetResource::class;

protected function getSteps(): array
{
return [
Step::make('Informations générales')
->schema([
// SheetResource::getTitleFormField(),
// SheetResource::getCodeFormField(),
// SheetResource::getTrainersFormField(),
// SheetResource::getTargetAudienceFormFieldset(),
SheetResource::getDurationFormFieldset(),
// SheetResource::getObjectivesFormSection(),
// SheetResource::getPrerequisitesFormSection(),
// SheetResource::getConditionsFormSection(),
])->columns(2),
Step::make('Programme')
->schema([
SheetResource::getDaysHiddenFormField(),
SheetResource::getScheduleFormRepeater(),
]),
Step::make('Compétences')
->schema([]),
Step::make("Grille d'Ă©valuation")
->schema([])
];
}
}
<?php

namespace App\Filament\Resources\SheetResource\Pages;

use App\Filament\Resources\SheetResource;
use Faker\Provider\Text;
use Filament\Actions;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Wizard\Step;
use Filament\Resources\Pages\CreateRecord;
use Symfony\Component\Console\Input\Input;

class CreateSheet extends CreateRecord
{
use CreateRecord\Concerns\HasWizard;

protected static string $resource = SheetResource::class;

protected function getSteps(): array
{
return [
Step::make('Informations générales')
->schema([
// SheetResource::getTitleFormField(),
// SheetResource::getCodeFormField(),
// SheetResource::getTrainersFormField(),
// SheetResource::getTargetAudienceFormFieldset(),
SheetResource::getDurationFormFieldset(),
// SheetResource::getObjectivesFormSection(),
// SheetResource::getPrerequisitesFormSection(),
// SheetResource::getConditionsFormSection(),
])->columns(2),
Step::make('Programme')
->schema([
SheetResource::getDaysHiddenFormField(),
SheetResource::getScheduleFormRepeater(),
]),
Step::make('Compétences')
->schema([]),
Step::make("Grille d'Ă©valuation")
->schema([])
];
}
}
toeknee
toeknee‱15mo ago
Are you planning on only using the wizard on create?
Chriis
ChriisOP‱15mo ago
Yes
toeknee
toeknee‱15mo ago
And not using it on edit?
Chriis
ChriisOP‱15mo ago
Yep
toeknee
toeknee‱15mo ago
Ok my bad
Chriis
ChriisOP‱15mo ago
I mean its how I see it, the edit would probably be with tabs however Oh my bad I didnt changed my test before sending evrything ... There is still my stupid try of double afterStateUpdate with the getDaysHiddenFormField() 😅 Passing the days from one step to the other (which in fact don't help me more xD) (for the model) Sheet
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Sheet extends Model
{
use HasFactory;

protected $casts = [
'duration' => 'array',
'objectives' => 'array',
'prerequisites' => 'array',
'schedule' => 'array',
'internal_competencies' => 'array',
];

protected $fillable = [
'title',
'code',
'duration',
'objectives',
'prerequisites',
'conditions',
'schedule',
'internal_competencies',
'certification_number',
'path',
'competency_framework_id',
'team_id',
'speciality_id',
'discipline_id',
];

public function trainers(): BelongsToMany
{
return $this->belongsToMany(User::class);
}

public function team(): BelongsTo
{
return $this->belongsTo(Team::class);
}

public function course(): BelongsTo
{
return $this->belongsTo(Course::class);
}

public function speciality(): BelongsTo
{
return $this->belongsTo(Speciality::class);
}
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Sheet extends Model
{
use HasFactory;

protected $casts = [
'duration' => 'array',
'objectives' => 'array',
'prerequisites' => 'array',
'schedule' => 'array',
'internal_competencies' => 'array',
];

protected $fillable = [
'title',
'code',
'duration',
'objectives',
'prerequisites',
'conditions',
'schedule',
'internal_competencies',
'certification_number',
'path',
'competency_framework_id',
'team_id',
'speciality_id',
'discipline_id',
];

public function trainers(): BelongsToMany
{
return $this->belongsToMany(User::class);
}

public function team(): BelongsTo
{
return $this->belongsTo(Team::class);
}

public function course(): BelongsTo
{
return $this->belongsTo(Course::class);
}

public function speciality(): BelongsTo
{
return $this->belongsTo(Speciality::class);
}
}
Want results from more Discord servers?
Add your server