GithubHelp home page GithubHelp logo

protonemedia / laravel-form-components Goto Github PK

View Code? Open in Web Editor NEW
811.0 28.0 95.0 282 KB

A set of Blade components to rapidly build forms with Tailwind CSS (v1.0 and v2.0) and Bootstrap 4/5. Supports validation, model binding, default values, translations, Laravel Livewire, includes default vendor styling and fully customizable!

Home Page: https://protone.media/blog/laravel-form-components-to-rapidly-build-forms-with-tailwind-css-and-bootstrap-4

License: MIT License

PHP 62.60% Blade 37.40%
laravel tailwindcss tailwind-css tailwindcss-plugin laravel-package laravel-framework bootstrap bootstrap4 bootstrap-4 bootstrap5

laravel-form-components's Introduction

⚠️ This package is deprecated. It doesn't support Livewire 3 and Tailwind 3 and won't be maintained anymore.

Laravel Form Components

Latest Version on Packagist Build Status Total Downloads Buy us a tree

A set of Blade components to rapidly build forms with Tailwind CSS v1, Tailwind CSS v2, Bootstrap 4 and Bootstrap 5. Supports validation, model binding, default values, translations, includes default vendor styling and fully customizable!

Sponsor this package!

❤️ We proudly support the community by developing Laravel packages and giving them away for free. If this package saves you time or if you're relying on it professionally, please consider sponsoring the maintenance and development. Keeping track of issues and pull requests takes time, but we're happy to help!

Laravel Splade

Did you hear about Laravel Splade? 🤩

It's the magic of Inertia.js with the simplicity of Blade. Splade provides a super easy way to build Single Page Applications using Blade templates. Besides that magic SPA-feeling, it comes with more than ten components to sparkle your app and make it interactive, all without ever leaving Blade.

Features

📺 Want to see this package in action? Join the live stream on November 19 at 14:00 CET: https://youtu.be/7eNZS4U7xyM

Requirements

  • PHP 8.0 or higher
  • Laravel 9.0

Installation

You can install the package via composer:

composer require protonemedia/laravel-form-components

If you're using Tailwind, make sure the right plugin (v1 or v2) is installed and configured.

Quick example

<x-form>
    @bind($user)
        <x-form-input name="last_name" label="Last Name" />
        <x-form-select name="country_code" :options="$options" />
        <x-form-select name="interests[]" :options="$multiOptions" label="Select your interests" multiple />

        <!-- \Spatie\Translatable\HasTranslations -->
        <x-form-textarea name="biography" language="nl" placeholder="Dutch Biography" />
        <x-form-textarea name="biography" language="en" placeholder="English Biography" />

        <!-- Inline radio inputs -->
        <x-form-group name="newsletter_frequency" label="Newsletter frequency" inline>
            <x-form-radio name="newsletter_frequency" value="daily" label="Daily" />
            <x-form-radio name="newsletter_frequency" value="weekly" label="Weekly" />
        </x-form-group>

        <x-form-group>
            <x-form-checkbox name="subscribe_to_newsletter" label="Subscribe to newsletter" />
            <x-form-checkbox name="agree_terms" label="Agree with terms" />
        </x-form-group>

        <x-form-submit />
    @endbind
</x-form>

Quick example form

Preface

At first sight, generating HTML forms with PHP looks great. PHP's power can make it less repetitive, and it's nice to resolve input values and validation states right from your PHP code. Still, it gets harder to keep your PHP code clean and neat whenever your forms get more complex. Often you end up with lots of custom code, writing extensions, and overriding defaults, just for the sake of adding some small thing to your form.

After years of trying all sorts of form builders, it feels like just writing most of the form in HTML is the most versatile solution. You can add helper texts, icons, tooltips, popovers, custom sections, and JavaScript integrations however and wherever you like. The power of Laravel Blade Components allows us to add all kinds of features without bringing the whole form-building process into PHP.

Let's take a look at this x-form example. The action attribute is optional, but you can pass a hard-coded, primitive value to the component using a simple HTML attribute. Likewise, PHP expressions and variables can be passed to attributes using the : prefix. Do you need Alpine.js or VueJS directives? No problem!

<x-form action="/api/user">
    <!-- ... -->
</x-form>
<x-form :action="route('api.user.store')" v-on:submit="checkForm">
    <!-- ... -->
</x-form>

Configuration

You can switch frameworks by updating the framework setting in the form-components.php configuration file. Check out the customization section on publishing the configuration and view files. If you're using the Livewire Stack with Laravel Jetstream, you probably want to set the framework configuration key to tailwind-forms-simple.

return [
    'framework' => 'bootstrap-4',
];

No further configuration is needed unless you want to customize the Blade views and components.

Usage

Input and textarea elements

The minimum requirement for an input or textarea is the name attribute.

<x-form-input name="company_name" />

Optionally you can add a label attribute, which can be computed as well.

<x-form-input name="company_name" label="Company name" />
<x-form-input name="company_name" :label="trans('forms.company_name')" />

You can also choose to use a placeholder instead of a label, and of course you can change the type of the element.

<x-form-input type="email" name="current_email" placeholder="Current email address" />

By default, every element shows validation errors, but you can hide them if you want.

<x-form-textarea name="description" :show-errors="false" />

Default value and binds

You can use the default attribute to specify the default value of the element.

<x-form-textarea name="motivation" default="I want to use this package because..." />

Binding a target

Instead of setting a default value, you can also pass in a target, like an Eloquent model. Now the component will get the value from the target by the name.

<x-form-textarea name="description" :bind="$video" />

In the example above, where $video is an Eloquent model, the default value will be $video->description.

Date Casting

If you use Eloquent's Date Casting feature, you can use the date attributes in your forms by setting the use_eloquent_date_casting configuration key to true. For compatibility reasons, this is disabled by default.

return [
    'use_eloquent_date_casting' => true,
];

You can either use the dates property or the casts property in your Eloquent model to specify date attributes:

class ActivityModel extends Model
{
    public $dates = ['finished_at'];

    public $casts = [
        'started_at'   => 'date',
        'failed_at'    => 'datetime',
        'completed_at' => 'date:d-m-Y',
        'skipped_at'   => 'datetime:Y-m-d H:i',
    ];
}
<x-form-input name="completed_at" :bind="$activity" />

In the example above, the default value will be formatted like 31-10-2021.

Binding a target to multiple elements

You can also bind a target by using the @bind directive. This will bind the target to all elements until the @endbind directive.

<x-form>
    @bind($video)
        <x-form-input name="title" label="Title" />
        <x-form-textarea name="description" label="Description" />
    @endbind
</x-form>

You can even mix targets!

<x-form>
    @bind($user)
        <x-form-input name="full_name" label="Full name" />

        @bind($userProfile)
            <x-form-textarea name="biography" label="Biography" />
        @endbind

        <x-form-input name="email" label="Email address" />
    @endbind
</x-form>

Override or remove a binding

You can override the @bind directive by passing a target directly to the element using the :bind attribute. If you want to remove a binding for a specific element, pass in false.

<x-form>
    @bind($video)
        <x-form-input name="title" label="Title" />
        <x-form-input :bind="$videoDetails" name="subtitle" label="Subtitle" />
        <x-form-textarea :bind="false" name="description" label="Description" />
    @endbind
</x-form>

Laravel Livewire

You can use the @wire and @endwire directives to bind a form to a Livewire component. Let's take a look at the ContactForm example from the official Livewire documentation.

use Livewire\Component;

class ContactForm extends Component
{
    public $name;
    public $email;

    public function submit()
    {
        $this->validate([
            'name' => 'required|min:6',
            'email' => 'required|email',
        ]);

        Contact::create([
            'name' => $this->name,
            'email' => $this->email,
        ]);
    }

    public function render()
    {
        return view('livewire.contact-form');
    }
}

Normally you would use a wire:model attribute to bind a component property with a form element. By using the @wire directive, this package will automatically add the wire:model attribute.

<x-form wire:submit.prevent="submit">
    @wire
        <x-form-input name="name" />
        <x-form-input name="email" />
    @endwire

    <x-form-submit>Save Contact</x-form-submit>
</x-form>

Additionally, you can pass an optional modifier to the @wire directive. This feature was added in v2.4.0. If you're upgrading from a previous version and you published the Blade views, you should republish them or update them manually.

<x-form wire:submit.prevent="submit">
    @wire('debounce.500ms')
        <x-form-input name="email" />
    @endwire
</x-form>

It's also possible to use the wire:model attribute by default. You may set the default_wire configuration setting to true or a modifier like debounce.500ms. This way, you don't need the @wire and @endwire directives in your views. You may still override the default setting by using the @wire directive, or by manually adding the wire:model attribute to a form element.

Select elements

Besides the name attribute, the select element has a required options attribute, which should be a simple key-value array.

$countries = [
    'be' => 'Belgium',
    'nl' => 'The Netherlands',
];
<x-form-select name="country_code" :options="$countries" />

You can provide a slot to the select element as well:

<x-form-select name="country_code">
   <option value="be">Belgium</option>
   <option value="nl">The Netherlands</option>
</x-form-select>

If you want a select element where multiple options can be selected, add the multiple attribute to the element. If you specify a default, make sure it is an array. This applies to bound targets as well.

<x-form-select name="country_code[]" :options="$countries" multiple :default="['be', 'nl']" />

You may add a placeholder attribute to the select element. This will prepend a disabled option.

This feature was added in v3.2.0. If you're upgrading from a previous version and you published the Blade views, you should republish them or update them manually.

<x-form-select name="country_code" placeholder="Choose..." />

Rendered HTML:

<select>
    <option value="" disabled>Choose...</option>
    <!-- other options... -->
</select>

Using Eloquent relationships

This package has built-in support for BelongsToMany, MorphMany, and MorphToMany relationships. To utilize this feature, you must add both the multiple and many-relation attribute to the select element.

In the example below, you can attach one or more tags to the bound video. By using the many-relation attribute, it will correctly retrieve the selected options (attached tags) from the database.

<x-form>
    @bind($video)
        <x-form-select name="tags[]" :options="$tags" multiple many-relation />
    @endbind
</x-form>

Checkbox elements

Checkboxes have a default value of 1, but you can customize it as well.

<x-form-checkbox name="subscribe_to_newsletter" label="Subscribe to newsletter" />

If you have a fieldset of multiple checkboxes, you can group them together with the form-group component. This component has an optional label attribute and you can set the name as well. This is a great way to handle the validation of arrays. If you disable the errors on the individual checkboxes, it will one show the validation errors once. The form-group component has a show-errors attribute that defaults to true.

<x-form-group name="interests" label="Pick one or more interests">
    <x-form-checkbox name="interests[]" :show-errors="false" value="laravel" label="Laravel" />
    <x-form-checkbox name="interests[]" :show-errors="false" value="tailwindcss" label="Tailwind CSS" />
</x-form-group>

Radio elements

Radio elements behave exactly the same as checkboxes, except the show-errors attribute defaults to false as you almost always want to wrap multiple radio elements in a form-group.

You can group checkbox and radio elements on the same horizontal row by adding an inline attribute to the form-group element.

<x-form-group name="notification_channel" label="How do you want to receive your notifications?" inline>
    <x-form-radio name="notification_channel" value="mail" label="Mail" />
    <x-form-radio name="notification_channel" value="slack" label="Slack" />
</x-form-group>

When you're not using target binding, you can use the default attribute to mark a radio element as checked:

<x-form-group name="notification_channel" label="How do you want to receive your notifications?">
    <x-form-radio name="notification_channel" value="mail" label="Mail" default />
    <x-form-radio name="notification_channel" value="slack" label="Slack" />
</x-form-group>

Old input data

When a validation errors occurs and Laravel redirects you back, the form will be re-populated with the old input data. This old data will override any binding or default value.

Handling translations

This package supports spatie/laravel-translatable out of the box. You can add a language attribute to your element.

<x-form-input name="title" language="en" :bind="$book" />

This will result in the following HTML:

<input name="title[en]" value="Laravel: Up & Running" />

To get the validation errors from the session, the name of the input will be mapped to a dot notation like title.en. This is how old input data is handled as well.

Customize the blade views

Publish the configuration file and Blade views with the following command:

php artisan vendor:publish --provider="ProtoneMedia\LaravelFormComponents\Support\ServiceProvider"

You can find the Blade views in the resources/views/vendor/form-components folder. Optionally, in the form-components.php configuration file, you can change the location of the Blade view per component.

Component logic

You can bind your own component classes to any of the elements. In the form-components.php configuration file, you can change the class per component. As the logic for the components is quite complex, it is strongly recommended to duplicate the default component as a starting point and start editing. You'll find the default component classes in the vendor/protonemedia/laravel-form-components/src/Components folder.

Prefix the components

You can define a prefix in the form-components.php configuration file.

return [
    'prefix' => 'tailwind',
];

Now all components can be referenced like so:

<x-tailwind-form>
    <x-tailwind-form-input name="company_name" />
</x-tailwind-form>

Error messages

By the default, the errors messages are positioned under the element. To show these messages, we created a FormErrors component. You can manually use this component as well. The element takes an optional bag attribute to specify the ErrorBag, which defaults to default.

<x-form>
    <x-form-input name="company_name" :show-errors="false" />

    <!-- other elements -->

    <x-form-errors name="company_name" />

    <x-form-errors name="company_name" bag="register" />
</x-form>

Submit button

The label defaults to Submit, but you can use the slot to provide your own content.

<x-form-submit>
    <span class="text-green-500">Send</span>
</x-form-submit>

Bootstrap

You can switch to Bootstrap 4 or Bootstrap 5 by updating the framework setting in the form-components.php configuration file.

return [
    'framework' => 'bootstrap-5',
];

There is a little of styling added to the form.blade.php view to add support for inline form groups. If you want to change it or remove it, publish the assets and update the view file.

Bootstrap 5 changes a lot regarding forms. If you migrate from 4 to 5, make sure to read the migration logs about forms.

Input group / prepend and append

In addition to the Tailwind features, with Bootstrap 4, there is also support for input groups. Use the prepend and append slots to provide the contents.

<x-form-input name="username" label="Username">
    @slot('prepend')
        <span>@</span>
    @endslot
</x-form-input>

<x-form-input name="subdomain" label="Subdomain">
    @slot('append')
        <span>.protone.media</span>
    @endslot
</x-form-input>

With Bootstrap 5, the input groups have been simplified. You can add as many items as you would like in any order you would like. Use the form-input-group-text component to add text or checkboxes.

<x-form-input-group label="Profile" >
    <x-form-input name="name" placeholder="Name" id="name" />
    <x-form-input-group-text>@</x-form-input-group-text>
    <x-form-input name="nickname" placeholder="Nickname" id="nickname" />
    <x-form-submit />
</x-form-input-group>

Floating labels

As of Bootstrap 5, you can add floating labels by adding the floating attribute to inputs, selects (excluding multiple), and textareas.

<x-form-input label="Floating Label" name="float_me" id="float_me" floating />

Help text

You can add block-level help text to any element by using the help slot.

<x-form-input name="username" label="Username">
    @slot('help')
        <small class="form-text text-muted">
            Your username must be 8-20 characters long.
        </small>
    @endslot
</x-form-input>

Testing

composer test

Changelog

Please see CHANGELOG for more information about what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Other Laravel packages

  • Laravel Analytics Event Tracking: Laravel package to easily send events to Google Analytics.
  • Laravel Blade On Demand: Laravel package to compile Blade templates in memory.
  • Laravel Cross Eloquent Search: Laravel package to search through multiple Eloquent models.
  • Laravel Eloquent Scope as Select: Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes and constraints by adding them as a subquery.
  • Laravel Eloquent Where Not: This Laravel package allows you to flip/invert an Eloquent scope, or really any query constraint.
  • Laravel FFMpeg: This package provides an integration with FFmpeg for Laravel. The storage of the files is handled by Laravel's Filesystem.
  • Laravel Paddle: Paddle.com API integration for Laravel with support for webhooks/events.
  • Laravel Verify New Email: This package adds support for verifying new email addresses: when a user updates its email address, it won't replace the old one until the new one is verified.
  • Laravel WebDAV: WebDAV driver for Laravel's Filesystem.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Treeware

This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.

laravel-form-components's People

Contributors

bradyrenting avatar dionpotkamp avatar laravel-shift avatar marcostmunhoz avatar mrl22 avatar pascalbaljet avatar punchrockgroin avatar ricardoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-form-components's Issues

Remove or alter the "mt-4"

Would be nice to able to control this via something like

<x-form-input field-class="mb-2" />

IMO too much spacing for a compact form, better to be adjustable.

Something like:

FormInput.php

        string $name,
        string $label = '',
        string $type = 'text',
        string $fieldClass = 'mt-4'
...

form-input.blade.php

        <div class="@if($type === 'hidden') hidden @else $fieldClass @endif">

How to mark the selected option in a select when editing a form?

I am working with bootstrap 4, the issue is that I have a form that is edit and always in the select I select the first option instead of editing me to mark the selected option and registered in the database.

Am I missing some other attribute or not?

Controller
    public function chooseTenant(){
        $tenants = Auth::user()->tenants->pluck('name','id');
        return view('switchAccount',['model'=>$tenants]);
    }
View
<x-form :action="route('choose_account')">
  <x-form-select name="tenant" :options="$model" :bind="4" label="{{__('Company')}}" />
  <x-form-submit>
        {{__('Cambiar cuenta')}}
  </x-form-submit>
</x-form>

help text in attribute

Hi,
I was wondering if it could be possible to pass help text directly through an attribute like any other parameters ?
something like this :

<x-form-input
  name="name"
  label="Name"
  help="Your name will not be visible"
/>

Thanks !!

Not working after installation

I run in the terminal:

composer require protonemedia/laravel-form-components

But when i try use in the project something like:

<x-form>
    @bind($user)
        <x-form-input name="last_name" label="Last Name" />
        <x-form-select name="country_code" :options="$options" />
        <x-form-select name="interests[]" :options="$multiOptions" label="Select your interests" multiple />

        <!-- \Spatie\Translatable\HasTranslations -->
        <x-form-textarea name="biography" language="nl" placeholder="Dutch Biography" />
        <x-form-textarea name="biography" language="en" placeholder="English Biography" />

        <!-- Inline radio inputs -->
        <x-form-group name="newsletter_frequency" label="Newsletter frequency" inline>
            <x-form-radio name="newsletter_frequency" value="daily" label="Daily" />
            <x-form-radio name="newsletter_frequency" value="weekly" label="Weekly" />
        </x-form-group>

        <x-form-group>
            <x-form-checkbox name="subscribe_to_newsletter" label="Subscribe to newsletter" />
            <x-form-checkbox name="agree_terms" label="Agree with terms" />
        </x-form-group>

        <x-form-submit />
    @endbind
</x-form>

I have error because my app dont see components from this package. What i need to do?

How to display data coming from a json field from DB?

Hello query I unify the form create and edit in a single view, since this library helps me not to make double form.

The question is that I have a field in the DB that is saved as JSON, the issue as I can do or access the JSON when I want to edit and show me that I have registered.

For example:

MYSQL
project_data = {"_5": "Color green","_6": "This is a custom text of the project"}

In the program logic I would do something like this:

In the model I made an attribute for faster access to it without having to veficiar the ID.

public function getCustomColorBotonAttribute($query){
     return (isset($this->project_data["_5"]) ? $this->project_data["_5"] : null);
}

And in the blade I call it like this but it always returns me null.
<x-form-input name="custom_colo_boton" label="Button color" :bind="$model->custom_color_boton"/>

livewire spatie translatable

Dear,

Creating a livewire bootstrap 4 input translatable results an wire:model="name[language]" instead of wire:model="name.language"

Many thanks for your feedack.

support for Livewire deferred updating?

With Livewire it is possible to defer updating.

E.g.

<input type="text" wire:model.defer="query">

Would be great if this can be supported in laravel-form-components.
E.g.

<x-form-input name="query" defer />

BTW. similar (but lower prio) request for lazy / debounce.

Reusable Form

Hi,

How Can use the same form for Create, update with livewire?

Unable to locate a class or view for component [form.form-input]

Maybe I'm missing something obvious here, but I've installed the package and I'm still getting errors trying to load any component, e.g.Unable to locate a class or view for component [form.form-input].

I thought perhaps it wasn't registering properly so I tried adding the Service Provider in app.config, but that made no difference.

Form group with radio is causing all radio buttons having checked attribute

We're using <x-form-group> with a couple of <x-form-radio> elements inside. When a value is selected and the form reloads due to validation errors, all radio elements have the checked='checked' attribute.

image

I think this is due to the fact that <x-form-radio> component is using a class which extends FormCheckbox and because of the presence of this line: https://github.com/protonemedia/laravel-form-components/blob/master/src/Components/FormCheckbox.php#L33

It could be fixed by changing FormRadio.php to the following:

<?php

namespace ProtoneMedia\LaravelFormComponents\Components;

class FormRadio extends Component
{
    use HandlesValidationErrors;
    use HandlesBoundValues;

    public string $name;
    public string $label;
    public $value;
    public bool $checked = false;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct(
        string $name,
        string $label = '',
        $value = 1,
        $bind = null,
        bool $default = false,
        bool $showErrors = true
    ) {
        $this->name       = $name;
        $this->label      = $label;
        $this->value      = $value;
        $this->showErrors = $showErrors;

        if (old($name) == $value) { <== CHANGE
            $this->checked = true;
        }

        if (!session()->hasOldInput() && $this->isNotWired()) {
            $boundValue = $this->getBoundValue($bind, $name);

            $this->checked = is_null($boundValue) ? $default : $boundValue == $value; <== CHANGE
        }
    }
}

Radio label click not working

image
In your example, click radio label not working.

See bootstrap 4 radio example

<div class="form-check form-check-inline">
  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1">
  <label class="form-check-label" for="inlineRadio1">1</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
  <label class="form-check-label" for="inlineRadio2">2</label>
</div>

Checkboxes and Radios broken after 2.5.1

After 2.5.1, it seems that Checkboxes and Radio buttons are broken when used in a Grouped setting. This is because the ID was previously being dynamically generated which was replaced to simply use the name attribute.

As the id attribute is the same for multiple inputs targeting the same option, the value will not change between different options.

Please see attached screenshot comparing this with 2.5.1 and 2.1.1:

2.5.1 (broken):
image

2.1.1 (working):
image

select multiple does not handle selected attribute

Hello,

When I do this :

@bind($model)
<x-form-select
  multiple
  name="categories[]"
  :options="App\Models\Categories::options()"
/>
@endbind($model)

Categories are saved, but they are not selected on page reload : no selected attribute on the <option> tags ,

am I doing it wrong ?

BTW this is my App\Models\Categories::options() :

[
   1 => "Justice",
   2 => "Culture",
   3 => "Agriculture"
]

select options with integers as keys breaks the form on user errors

For this issue I copied the example from the readme:

<x-form-select name="country_code">
   <option value="be">Belgium</option>
   <option value="nl">The Netherlands</option>
</x-form-select>

suppose that we generated the above options with a $options array. This will work:

$options = ['be' => 'Belgium', 'nl' => 'The Netherlands'];
<x-form-select name="country_code" :options="$options">

But the following will not work correctly:

$options = ['Belgium','The Netherlands'];
<x-form-select name="country_code" :options="$options">

The above will generate this HTML:

<select name="country_code">
                            <option value="0">
                    Belgium
                </option>
                            <option value="1">
                    The Netherlands
                </option>
                    </select>

This will not correctly bind the old values of the form when the user made an error. The form will be reloaded with the error messages in it but without the selected item from the select list.
The reason for this lies in the file src/Components/FormSelect.php on line 51: if ($this->selectedKey === $key) { this will return false every time because $this->selectedKey is a string and $key is an integer. Is it possible to change the === to ==?
The example with the country_code does not make much sense at first. But if I want to generate the form options from an eloquent relation (and other data than country codes), I have exactly this problem. The ID of the foreign key is an int and the above mentioned if will never return true.

not possible for select option: selected + disabled?

Liking this package!

Similar to #44 , I want to add header (and/or separator) options to a select component. But, I want them to be disabled and selected.

The issue: <x-form-select> does not support an option with disabled selected.

E.g. this works for a regular select:

<select>
  <option value="" disabled selected>please select...</option>
  <option value="1">one</option>
</select>

Result is that "please select..." is selected (as expected).

And this does not:

<x-form-select name="...">
  <option value="" disabled selected>please select...</option>
  <option value="1">one</option>
</select>

Result is that "one" is selected.

Note: using in combination with Livewire v2.

Before Submit Feature Request

If we could have before submit feature in the package, it could help us develop faster and this package is suitable for implementing it as it deals with form.

Expectation:
Before submit is a slot where we can put HTML element and it loads on blank modal with buttons to confirm before form submission

Form action

I don't see where to specify an action route/url for forms?

bind issue

when using bind with the x-form-input , doesn't show the correct value, especially the value is 0. I guess the issue is bound value.

$default = $this->getBoundValue($bind, $name) ?: $default;

to

$default = $this->getBoundValue($bind, $name) ?? $default;

in \src\Components\HandlesDefaultAndOldValue.php.

disabled / required attributes passed with Blade

Hy!

I wonder how can I specify with Blade a "disabled" attribute to the component

In my case, clients can be prevent from updating by the admin
For example, if I do

//$clientIsDisabled='disabled'
<x-form-input name="client_name" label="Name *" required {{ $clientIsDisabled }} />

The input is not rendered

Actually, I do something like this:

@if($clientIsDisabled)
    <x-form-input name="client_name" label="Name *" required disabled />
@else
    <x-form-input name="client_name" label="Name *" />
@endif

But it's ugly...
Do not use the component in that case is maybe the simplest solution?

Do I miss something?
How do you do in that situation?

Thank you!

Error on ReadMe

You have a error on ReadMe I think when you use the x-form-select with multiple your name needs to be like this name="country_code[]" otherwise you don't get the array on values choosen.

Date Casting

I don't think this is a bug as such - perhaps a feature suggestion

We've got a form that looks like this

image

Valid From & Expires At are date fields. Ex: <x-form-input type="date" name="expires_at" label="Expires" placeholder="Expires"/>

The model also has $casts, like this so we can use Carbon on the dates.
We're UK based so we need to modify the date format.

    protected $casts = [
        'valid_from' => 'date:Y-m-d',
        'expires_at' => 'date:Y-m-d',
    ];

This works well for us. The issue comes when we try to edit

This is the blade, where we are binding the form to a model

@bind($applicantQualification)
        ...
       <div class="col">
                    <div class="form-floating">
                        {{ dump($applicantQualification->valid_from) }}
                        <x-form-input type="date" name="valid_from" label="Valid From" placeholder="Valid From"/>
                    </div>
                </div>
                <div class="col">
                    <div class="form-floating">
                        {{ dump($applicantQualification->expires_at) }}
                        <x-form-input type="date" name="expires_at" label="Expires" placeholder="Expires"/>
                    </div>
                </div>
                ...
@endbind

image

This is the rendered HTML

<input class="form-control" placeholder="Valid From" type="date" name="valid_from" value="2021-04-28 00:00:00" id="auto_id_valid_from">

The date input is not being populated as it is invalid value="2021-04-28 00:00:00"

We need to unbind / alter the bind such as $applicantQualification->valid_from->format('d/m/Y')

We also have an assessor which we are using to transform the date to UK format. Ex

    public function getValidFromAttribute( $value ) {
        if ( $value ) {
            return Carbon::parse( $value )->format( config( 'app.date_format' ) );
        }

        return null;
    }

We could use this to change it to US format that would solve this issue, however it would cause issues / break Lara standards later on in the app.

My best work around currently is something like this

@php
                           $valid_from = null;
                           if ($applicantDocument->valid_from) {
                               $valid_from = $applicantDocument->valid_from->format('Y-m-d');
                           }
                       @endphp
                       <x-form-input type="date" name="valid_from" label="Valid From" placeholder="Valid From" :bind="false" :default="$valid_from"/>

Laravel Collective's HTML package has a concept of Form Accessors which would solve this issue. Are there any plans for similar Form Accessors.. These would be a great help to people that don't use the US date format (or need any other type of mutations).

Any thoughts?

Memory usage

Hi, thanks for your package.

I decided to use it in my project, and immediately saw that the rendering speed (decreased) and the amount of memory usage increased significantly (I display this in the screenshot).

I wanted to ask you if this is due to the package or to the fact that the blade components themselves are working slowly, as previously there was little experience with them. Thanks to.
Снимок экрана 2021-11-15 в 14 14 35

FormCheckbox old value

image

ProtoneMedia\LaravelFormComponents\Components\FormCheckbox.
Starts on line 45
... if (is_array($boundValue)) { $this->checked = in_array($value, $boundValue); return; } ...
What about collection support?

Feature request: Livewire modifier attribute

Would be nice to be able to:

@wire
    <x-form-input name="first_name" modifier="defer" />
@endwire

Which would output:

    <input wire:model.defer="first_name" />

I could hack the published views but it's cleaner if it came from Component.

Radio inputs - Non-string values considered false are not bound (in edit view or after wrong validation)

Hi,

I have boolean field create_role (0 or 1) from my database that I've bound to a radio input :

@bind($user)
       <x-form-group class="ms-3" label="Is this user able to create new articles?" inline>
           <x-form-radio name="create_article" value="0" label="no" default/>
           <x-form-radio name="create_article" value="1" label="yes"/>
       </x-form-group>
@endbind

But if I edit or update with a wrong validation another field, value 0 (false is the same) is not bound.
Its because of the comparison in the ProtoneMedia\LaravelFormComponents\Components\FormRadio.php file at line 31 and line 38

Is there any simple way you use to fix that problem? I've already fixed it by my own but not sure its the better one...

I have modified the same file as before like this :

<?php

namespace ProtoneMedia\LaravelFormComponents\Components;

class FormRadio extends Component
{
    use HandlesValidationErrors;
    use HandlesBoundValues;

    public string $name;
    public string $label;
    public $value;
    public bool $checked = false;

    public function __construct(
        string $name,
        string $label = '',
        $value = 1,
        $bind = null,
        bool $default = false,
        bool $showErrors = false
    ) {
        $this->name       = $name;
        $this->label      = $label;
        $this->value      = $value;
        $this->showErrors = $showErrors;

        $inputName = static::convertBracketsToDots($name);

        //modified line
        if (!is_null(old($inputName))) {
            //modified line
            $this->checked = $this->toStringIfFalse(old($inputName)) == $value;
        }

        if (!session()->hasOldInput() && $this->isNotWired()) {
            $boundValue = $this->getBoundValue($bind, $name);

            if (!is_null($boundValue)) {
                //modified line
                $this->checked = $this->toStringIfFalse($boundValue) == $this->value;
            } else {
                $this->checked = $default;
            }
        }
    }

    /**
     * Generates an ID by the name and value attributes.
     *
     * @return string
     */
    protected function generateIdByName(): string
    {
        return "auto_id_" . $this->name . "_" . $this->value;
    }

    /**
     * All of the non-string boolean values considered false are casted to string
     * so that it can be correctly compared with the input radio value
     * (string values considered false like "0" or "" are already correctly compared)
     * 
     * @return string
     */
    protected function toStringIfFalse($value)
    {
        if($value === false ||
           $value === 0 ||
           $value === 0.0 ||//im not sure this one
           $value === -0.0 // and this one will find concrete cases...
        ){
            return var_export($value, true);
        }
        return $value;
    }
}

Feature: Thoughts on "rich" components?

Hi team,

I'm just replaced the (hundred) of various forms in my app with this library, and will be using it exclusively for the app going forwards.

Have you thought about richer components? Date pickers, rich text, markdown, etc?

I'm thinking that the javascript would go on a stack, so it's not called in by default in the library for anyone not using the rich components.

Select (tailwind 2) doesn't display first option - malformed html

in resources/views/tailwind-2/form-select.blade.php - the main <select> tag is not properly closed, which means that the first option is not displayed, and the resulting rendered html is invalid.

Solution: Add closing > e.g. on line 21

diff --git resources/views/vendor/form-components/tailwind-2/form-select.blade.php resources/views/vendor/form-components/tailwind-2/form-select.blade.php
index ba7abfe..704d86d 100644
--- resources/views/vendor/form-components/tailwind-2/form-select.blade.php
+++ resources/views/vendor/form-components/tailwind-2/form-select.blade.php
@@ -18,6 +18,7 @@
             @if($multiple)
                 multiple
             @endif
+        >
 
             @forelse($options as $key => $option)
                 <option value="{{ $key }}" @if($isSelected($key)) selected="selected" @endif>

checked checkbox on edit won't uncheck (boolean)

Field: attention_grabber (boolean)

When creating an object, the value is set properly (1 if checked, 0 if unchecked)
When updating an object, if attention_grabber is unchecked, then the value updates correctly if checked (ie 1)
However when updating an object, if attention_grabber is checked, the value stays checked even if unchecked.

I tried changing the field to an input value (and set manually to 0 or 1) and it works well.

I assume there is something going on with my code but I don't know what's wrong (very basic):

// doesn't work on update to uncheck
<x-form-checkbox name="attention_grabber" label="Attention Grabber" />

// works on any situation
<x-form-input name="attention_grabber" label="Attention Grabber" />

// also works
<x-form-group name="attention_grabber" label="Attention Grabber" inline>
  <x-form-radio name="attention_grabber" value="1" label="Yes" />
  <x-form-radio name="attention_grabber" value="0" label="No" />
</x-form-group>

Feature: Changing framework or multiple frameworks

My site uses tailwind and bootstrap. Is it possible to use multiple frameworks?

For example on bootstrap4_index.blade.php I declare to use framework bootstrap 4 and on tailwind_index.blade.php I declare to use tailwind framework.
Or using prefixes with a framework, where you can set a prefix bound to a framework? For example and

Bootstrap 5 support ?

Hi there, does this package support Bootstrap 5 ?
I wanna use it with a new admin panel that i'm going to build.

BS5 Append Validation

Just dropping this quick issue here, I'll see if I can do a PR later.

If we have a BS5 field with an append like this

image

            <div class="col">
                <x-form-input-group label="Current Years Gross Profit %">
                    <x-form-input name="current_year_gross_profit"></x-form-input>
                    <x-form-input-group-text>%</x-form-input-group-text>
                </x-form-input-group>
            </div>

...and validation fails, the validation classes split the append group, resulting in this

image

Prepend works fine...

image

Tailwind custom-forms still required?

Hello,

In the README.md file it reads
Make sure the Tailwind plugin is installed and added to your tailwind.config.js

Is this the case when Tailwind v2 is used, as Tailwind v2 replaced custom-forms with its included forms.

Thank you,

Unable to get select to work with relationships with Livewire

Following the docs, I'm trying to get Livewire to work with relationships and a multi-select.

Code is as follows:

<x-form wire:submit.prevent="submit">
    @wire
            <x-form-input name="post.title" label="Title" :readonly="!$isEditing" />

            <x-form-textarea name="post.description" label="Description" :readonly="!$isEditing" />

            @if($isEditing)
                <x-form-select name="post.tags[]" :options="$this->allTags" multiple many-relation label="Applicable Tags" />
            @endif
    @endwire
</x-form>

Whilst the options are populated, the chosen ones are not selected when the form is shown, and any chosen ones are not saved when the form is submitted.

Livewire support

Thanks for this library, saves me a lot of time.

I noticed when I'm using Livewire the errors don't show. It's because in Livewire the errors are not in the session, so this line always returns an empty bag.

I also noticed that the check for hasError is not that usefull because in the layouts it's always wrapped in the @error directive. Like form-errors.blade.php

Maybe just get rid of the hasError part and just use the showError, it should be compatible with Livewire that way and you don't double check for errors.

What's your opinion on this?

default value for select

I have tried to change the default value for a select.

<x-form-select name="country_code" :default="['nl']">
    <option value="be">Belgium</option>

    <option value="nl" >The Netherlands</option>

</x-form-select>

but it always shows Belgium.
how can I change it ?

Required fields

When developing forms it is common to mark the required fields to differentiate them from the rest. In many cases a red asterisk is used behind the label.

I think it would be nice to add a way to identify these fields. Here is a simple way to implement it:
A "required" tag (<x-form-input name = "name" required />) could generate this code:

<div class = "form-group">
  <label for = "auto_id_name" class = "required"> Name </label>
  <div class = "input-group">
    <input class = "form-control" type = "text" name = "name" value = "" id = "auto_id_name" required>
  </div>
</div>

The appearance of the label can be controlled by CSS (label.required) and optionally the "required" modifier in the input tag can help with data validation.

Unable to bind the data.

Hi,

I am very thankful for your package.

I have a small issue in which I am unable to understand how to use the binding.

When I am trying to use the same form for both create and update separate functions, I was able to save the data but unable to see the previous data but was able to save the edit from.

Thanks in Advance for the package.

Screenshot_20220131_022959

Checkbox problems

I have a problem with checkboxes checked.

In this version, the checkboxes simply disappear.

<x-form-checkbox
    name="permissions[]"
    :show-errors="false"
    value="{{ $permission->id }}"
    label="{{ $permission->description }}"
    @if($role->permissions->contains($permission->id))
        default
    @endif
/>

This also does nothing.

<x-form-checkbox
    name="permissions[]"
    :show-errors="false"
    value="{{ $permission->id }}"
    label="{{ $permission->description }}"
    :bind="true"
/>

Bootstrap 4 form-input error message in the wrong place

When I tried to validate the input, form-input didn't show any error message. So, I checked up the HTML and it shows that the error message are placed outside the input-group class

<div class="input-group">
     <input/>
</div>

{!! $help ?? null !!}

@if($hasErrorAndShow($name))
     <x-form-errors :name="$name" />
@endif

which should be inside it, or more precisely placed below the input

<div class="input-group">
     <input/>

     {!! $help ?? null !!}

     @if($hasErrorAndShow($name))
          <x-form-errors :name="$name" />
     @endif
</div>

Question: How to Add a empty Field to Select

Hi there,

thank you very much for your great Work on this Package.

It would be great if you could point me to the right direction.

I would like to use the Select field with an empty entry on top (value="") with a Label "please choose a option", for example in a Livewire-Form for searching a table.
Shure, i could use array_merge([''=>'please choose'],$values); in the :options= prop, but maybe there is a neater way.

Thanks a lot,

Conrad

Render does not return output

Why does the render-method output a path instead of the view representation? According to the docs, it should return the content for the view:


Base method doc:

Get the view / view contents that represent the component.

How can I render the output for the component from PHP?

I tried this, but as the render returns just a path, I don't get the actual output:

				$autocomplete = new FormAutocomplete(
					'id',
					'label'
				);
				echo $autocomplete->render();

Problem when using livewire together with labels

Hello,

It is because of randomly generated id - livewire can't properly match dom elements or something like this. It result in lost focus on input.

I suggest to fix examples in readme and/or add information that livewire require to pass id.
Alternatively we could disable random id when using livewire.

ErrorBag Definition

Hello,

thank you very much for your work and willing to share it.

Is it possible to set the ErrorBag in the x-form element? It would be useful when displaying more than one form on a single page.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.