October 22, 2024
Chicago 12, Melborne City, USA
PHP

Filament 3: TextInput numeric field truncating large numbers to first two digits?


I’m having an issue with Filament 3 where a numeric TextInput field is automatically truncating numbers. For example, when I enter "1000", it immediately becomes "10".
Here’s my current code in a Resource form:

<?php

namespace App\Filament\Resources;

use App\Enum\PurchaseOrderStatus;
use App\Filament\Resources\PurchaseOrderResource\Pages;
use App\Models\PurchaseOrder;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ActionGroup;
use Filament\Tables\Table;

class PurchaseOrderResource extends Resource
{
    protected static ?string $model = PurchaseOrder::class;

    protected static ?string $navigationIcon = 'heroicon-o-shopping-cart';
    protected static ?string $navigationGroup = 'Manufacturing Management';

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Wizard::make([
                    // Step 1: General PO Information
                    Forms\Components\Wizard\Step::make('PO Details')
                        ->schema([
                            Forms\Components\Select::make('supplier_id')
                                ->relationship('supplier', 'name')
                                ->required()
                                ->label('Supplier'),

                            Forms\Components\TextInput::make('po_number')
                                ->required()
                                ->reactive()
                                ->default(fn() => self::generateUniquePONumber()) // Auto-generate unique PO number
                                ->maxLength(50)
                                ->label('PO Number')
                                ->readonly(), // Prevent manual editing,

                            Forms\Components\DatePicker::make('po_date')
                                ->required()
                                ->label('PO Date'),

                            Forms\Components\DatePicker::make('expected_delivery_date')
                                ->label('Expected Delivery Date'),

                            Forms\Components\Select::make('status')
                                ->options(PurchaseOrderStatus::class)
                                ->enum(PurchaseOrderStatus::class)
                                ->required()
                                ->label('Status'),

                            Forms\Components\TextInput::make('total_amount')
                                ->numeric()
                                ->label('Total Amount')
                                ->visible(fn($record) => $record !== null)
                                ->prefix('£E') // Add the prefix here
                            ->disabled(),

                            Forms\Components\Textarea::make('notes')
                                ->columnSpanFull()
                                ->label('Notes'),
                        ])->columns(2),

                    // Step 2: Material Entries
                    Forms\Components\Wizard\Step::make('Material Details')
                        ->schema([
                            Forms\Components\Repeater::make('purchaseOrderItems') // Changed from po_details to purchaseOrderItems
                            ->relationship()
                                ->label('Materials')
                                ->schema([
                                    Forms\Components\Select::make('material_id')
                                        ->options(function () {
                                            return \App\Models\Material::pluck('material_name', 'id');
                                        })
                                        ->required()
                                        ->label('Material')
                                        ->searchable(),
                                    Forms\Components\TextInput::make('quantity_in_kilos')
                                        ->numeric()
                                        ->required()
                                        ->label('Quantity (kilos)')
                                        ->reactive(),
                                    Forms\Components\TextInput::make('quantity_in_grams')
                                        ->required()
                                        ->numeric()
                                        ->default(0)
                                        ->reactive()
                                        ->readOnly(),
                                    Forms\Components\TextInput::make('unit_price')
                                        ->numeric()
                                        ->required()
                                        ->label('Unit Price')
                                        ->reactive(),
                                    Forms\Components\TextInput::make('subtotal')
                                        ->disabled()
                                        ->label('Subtotal')
                                        ->dehydrated(false)
                                        ->reactive()
                                        ->prefix('£E')
                                        ->formatStateUsing(fn($state) => number_format($state ?? 0, 2)),
                                ])
                                ->minItems(1)
                                ->columns(5)
                                ->columnSpanFull()
                                ->reactive(),
                        ]),
                ])->columnSpanFull()
                    ->submitAction('Save PO')
            ]);

    }

    private static function generateUniquePONumber(): string
    {
        do {
            $poNumber="OPO-" . mt_rand(100000, 999999);
        } while (PurchaseOrder::where('po_number', $poNumber)->exists());

        return $poNumber;
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('supplier.name')
                    ->numeric()
                    ->sortable(),
                Tables\Columns\TextColumn::make('po_number')
                    ->searchable(),
                Tables\Columns\TextColumn::make('po_date')
                    ->date()
                    ->sortable(),
                Tables\Columns\TextColumn::make('expected_delivery_date')
                    ->date()
                    ->label('Delivery Date')
                    ->sortable(),
                Tables\Columns\TextColumn::make('status'),
                Tables\Columns\TextColumn::make('total_amount')
                    ->numeric()
                    ->formatStateUsing(fn($state) => '£E' . number_format($state, 2)) // Add the prefix and format the number
                    ->sortable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('updated_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                //
            ])
            ->actions([
                ActionGroup::make(
                    [
                        Tables\Actions\EditAction::make(),
                        Tables\Actions\ViewAction::make(),
                        Tables\Actions\DeleteAction::make(),
                    ]
                )
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListPurchaseOrders::route('/'),
            'create' => Pages\CreatePurchaseOrder::route('/create'),
            'edit' => Pages\EditPurchaseOrder::route('/{record}/edit'),
        ];
    }

}

This is work fine and problem start appear after i tried to set state to change quntit in grams based on quantity in kilos
Here’s my current code cause the problem:

Forms\Components\TextInput::make('quantity_in_kilos')
    ->numeric()
    ->required()
    ->label('Quantity (kilos)')
    ->reactive()
    ->afterStateUpdated(function (Get $get, Set $set, $state) {
        // Convert kilos to grams (1 kilo = 1000 grams)
        $grams = $state * 1000;
        $set('quantity_in_grams', $grams);
    })

Adding numeric constraints:

->minValue(0)
->maxValue(999999.99)

Using input mode and step:

->inputMode('decimal')
->step('0.01')

Using mask:

->mask(fn (Forms\Components\TextInput\Mask $mask) => $mask
    ->numeric()
    ->decimalPlaces(2)
    ->decimalSeparator('.')
    ->thousandsSeparator(',')
    ->minValue(0)
)

Environment:

Laravel 10
Filament 3
PHP 8.2

Expected behavior:
When I enter "1000", it should stay as "1000"
Actual behavior:
When I enter "1000", it immediately becomes "10"
Question:
How can I prevent Filament from truncating large numbers in a numeric TextInput field? I need to be able to enter numbers up to 999,999.99 with proper decimal support.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video