Using an enum with a toggle

Does anyone know of a clean way to use enums with toggles? One of my models has a status column with only 2 values - active and inactive. I want the toggle to switch between these values. I'd prefer to use an enum vs a boolean because I want to display the status using a badge (with labels, icons and colors).
15 Replies
awcodes
awcodes4mo ago
Well, an enum depends on a specific value, but a toggle is either true or false. If it can only be true or false, then an enum is probably not the right approach.
binaryfire
binaryfire4mo ago
True. It's more about re-using the badge color / icon / label in the UI. The form field is an "Active" toggle but the table column is a Status column with "Active" and "Inactive" badges. I'm using formatStateUsing for the column but now I need to re-use the same badge in an infolist and a second table.
awcodes
awcodes4mo ago
All of that is still a bool and not an enum though. But it’s possible as long as you do a little extra work to convert the enum’s value to a truthy or falsy value.
binaryfire
binaryfire4mo ago
Yeah cool. A custom cast might do it.
awcodes
awcodes4mo ago
But it still doesn’t sound like an enum is right for this. But it’s your app. 😅 Like, If you’re trying to plan for possible future values like draft, scheduled, published, then it shouldn’t be a toggle or bool to start with. There’s nothing wrong with a select that only has 2 options.
binaryfire
binaryfire4mo ago
Yeah maybe not. Was trying to tap into HasIcon, HasColor and HasLabel since that makes re-use easier. But changing the attribute type probably isn't the right approach... I'll keep it as a boolean and figure out another way to re-use the badge styling
awcodes
awcodes4mo ago
But the badge can be based on a callback. So it shouldn’t matter.
binaryfire
binaryfire4mo ago
I'll need to set callbacks for color, icon and formatStateUsing each time. But I'm only rendering it as a badge 3 times so no big deal
awcodes
awcodes4mo ago
Sometimes you have to massage the return.
binaryfire
binaryfire4mo ago
My app and I aren't on an intimate enough basis for that
awcodes
awcodes4mo ago
Sounds like you might be. Don’t get caught in the in between. It’s still just input / output. Point still stands a toggle is true / false. An enum is not. 😅 Otherwise they’d call it a Boolean.
binaryfire
binaryfire4mo ago
I'll keep it as a boolean but still use an enum to store the icon, color and label values of each state. Then just call CollectionEnabled::true->getColor() / CollectionEnabled::false->getColor() etc. when I need to retrieve values in closures. Still my favorite type of class for reusing things like that. Main thing is being able to change the appearance of the Active / Inactive badges in one place rather than 3
dissto
dissto4mo ago
I did something similar in one of my projects. Maybe this helps 😊
enum GroupStatus: int implements HasColor, HasIcon, HasLabel
{
case Active = 1;
case Inactive = 0;

public function getLabel(): ?string
{
return match ($this) {
self::Active => 'Active',
self::Inactive => 'Inactive',
};
}

public function getColor(): string|array|null
{
return match ($this) {
self::Active => Color::Green,
self::Inactive => Color::Red,
};
}

public function getIcon(): ?string
{
return match ($this) {
self::Active => 'heroicon-o-check-circle',
self::Inactive => 'heroicon-o-x-circle',
};
}
}

//

ToggleButtons::make('status')
->label(__('resources/group.form.fields.status.label'))
->hint(__('resources/group.form.fields.status.hint'))
->helperText(__('resources/group.form.fields.status.helperText'))
->grouped()
->options(GroupStatus::class)
->default(GroupStatus::Active->value),

// migration
$table->unsignedTinyInteger('status')->default(GroupStatus::Active->value);
enum GroupStatus: int implements HasColor, HasIcon, HasLabel
{
case Active = 1;
case Inactive = 0;

public function getLabel(): ?string
{
return match ($this) {
self::Active => 'Active',
self::Inactive => 'Inactive',
};
}

public function getColor(): string|array|null
{
return match ($this) {
self::Active => Color::Green,
self::Inactive => Color::Red,
};
}

public function getIcon(): ?string
{
return match ($this) {
self::Active => 'heroicon-o-check-circle',
self::Inactive => 'heroicon-o-x-circle',
};
}
}

//

ToggleButtons::make('status')
->label(__('resources/group.form.fields.status.label'))
->hint(__('resources/group.form.fields.status.hint'))
->helperText(__('resources/group.form.fields.status.helperText'))
->grouped()
->options(GroupStatus::class)
->default(GroupStatus::Active->value),

// migration
$table->unsignedTinyInteger('status')->default(GroupStatus::Active->value);
dissto
dissto4mo ago
Not a toggle per-se but hey 😊
No description
binaryfire
binaryfire4mo ago
Thanks for sharing 🙂 I ended up keeping it as a boolean but also used an enum to store the label / icon / color values for reuse across classes. It's a bit of a unusual use case - I wanted to keep the toggle in forms but show it as an Active / Inactive badge in tables and infolists.