Skip to content

Commit

Permalink
feature #3530 Render date and time fields using native form widgets b…
Browse files Browse the repository at this point in the history
…y default (javiereguiluz)

This PR was merged into the 3.0.x-dev branch.

Discussion
----------

Render date and time fields using native form widgets by default

EasyAdmin displays by default the date/time/datetime fields using the default Symfony Forms design (i.e. using `<select>` choices). The main issue is that the year is limited to +/- 5 years, which is not very useful in most apps:

![image](https://user-images.githubusercontent.com/73419/87225950-fae15600-c390-11ea-924f-a1b68e955d1a.png)

So, this PR adds 3 new config methods for date/time/datetime fields:

```php
->renderAsNativeWidget()  // HTML5 native widget
->renderAsChoice()        // <select> lists
->renderAsText()          // single input[text]
```

By default, all these fields are now rendered using HTML5 native widgets:

![image](https://user-images.githubusercontent.com/73419/87225992-3714b680-c391-11ea-9e21-87bb7f2bd8ef.png)

Thanks to browsers improvements, we no longer need JavaScript datepickers, because native widgets are great and are localized into the users language:

![image](https://user-images.githubusercontent.com/73419/87226011-4f84d100-c391-11ea-9bf0-ac16abc7671e.png)

Commits
-------

464f59c Render date and time fields using native form widgets by default
  • Loading branch information
javiereguiluz committed Jul 13, 2020
2 parents f4f56e2 + 464f59c commit 6d0170d
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 4 deletions.
7 changes: 7 additions & 0 deletions assets/css/easyadmin-theme/fields.scss
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@
text-transform: uppercase;
}

// Date, Time and DateTime fields
.field-datetime input[type="datetime-local"].form-control,
.field-date input[type="date"].form-control,
.field-time input[type="time"].form-control {
width: auto;
}

// Language field
.field-language .badge-language {
border: 2px solid var(--gray-300);
Expand Down
12 changes: 12 additions & 0 deletions src/Field/Configurator/DateTimeConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
$formattedValue = $this->intlFormatter->formatTime($field->getValue(), null, $timePattern, $timezone);
}

$widgetOption = $field->getCustomOption(DateTimeField::OPTION_WIDGET);
if (DateTimeField::WIDGET_NATIVE === $widgetOption) {
$field->setFormTypeOption('widget', 'single_text');
$field->setFormTypeOption('html5', true);
} elseif(DateTimeField::WIDGET_CHOICE === $widgetOption) {
$field->setFormTypeOption('widget', 'choice');
$field->setFormTypeOption('html5', true);
} elseif(DateTimeField::WIDGET_TEXT === $widgetOption) {
$field->setFormTypeOption('widget', 'single_text');
$field->setFormTypeOption('html5', false);
}

$field->setFormattedValue($formattedValue);

$doctrineDataType = $entityDto->getPropertyMetadata($field->getProperty())->get('type');
Expand Down
46 changes: 45 additions & 1 deletion src/Field/DateField.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class DateField implements FieldInterface
use FieldTrait;

public const OPTION_DATE_PATTERN = 'datePattern';
public const OPTION_WIDGET = 'widget';

public static function new(string $propertyName, ?string $label = null): self
{
Expand All @@ -24,7 +25,8 @@ public static function new(string $propertyName, ?string $label = null): self
->addCssClass('field-date')
// the proper default values of these options are set on the Crud class
->setCustomOption(self::OPTION_DATE_PATTERN, null)
->setCustomOption(DateTimeField::OPTION_TIMEZONE, null);
->setCustomOption(DateTimeField::OPTION_TIMEZONE, null)
->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
}

/**
Expand Down Expand Up @@ -59,4 +61,46 @@ public function setFormat(string $dateFormatOrPattern): self

return $this;
}

/**
* Uses native HTML5 widgets when rendering this field in forms
*/
public function renderAsNativeWidget(bool $asNative = true): self
{
if (false === $asNative) {
$this->renderAsChoice();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
}

return $this;
}

/**
* Uses <select> lists when rendering this field in forms
*/
public function renderAsChoice(bool $asChoice = true): self
{
if (false === $asChoice) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_CHOICE);
}

return $this;
}

/**
* Uses <input type="text"> elements when rendering this field in forms
*/
public function renderAsText(bool $asText = true): self
{
if (false === $asText) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_TEXT);
}

return $this;
}
}
50 changes: 49 additions & 1 deletion src/Field/DateTimeField.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ final class DateTimeField implements FieldInterface
self::FORMAT_NONE => '',
];

public const WIDGET_NATIVE = 'native';
public const WIDGET_CHOICE = 'choice';
public const WIDGET_TEXT = 'text';

public const OPTION_DATETIME_PATTERN = 'dateTimePattern';
public const OPTION_TIMEZONE = 'timezone';
public const OPTION_WIDGET = 'widget';

public static function new(string $propertyName, ?string $label = null): self
{
Expand All @@ -49,7 +54,8 @@ public static function new(string $propertyName, ?string $label = null): self
->addCssClass('field-datetime')
// the proper default values of these options are set on the Crud class
->setCustomOption(self::OPTION_DATETIME_PATTERN, null)
->setCustomOption(self::OPTION_TIMEZONE, null);
->setCustomOption(self::OPTION_TIMEZONE, null)
->setCustomOption(self::OPTION_WIDGET, self::WIDGET_NATIVE);
}

/**
Expand Down Expand Up @@ -104,4 +110,46 @@ public function setFormat(string $dateFormatOrPattern, string $timeFormat = self

return $this;
}

/**
* Uses native HTML5 widgets when rendering this field in forms
*/
public function renderAsNativeWidget(bool $asNative = true): self
{
if (false === $asNative) {
$this->renderAsChoice();
} else {
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_NATIVE);
}

return $this;
}

/**
* Uses <select> lists when rendering this field in forms
*/
public function renderAsChoice(bool $asChoice = true): self
{
if (false === $asChoice) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_CHOICE);
}

return $this;
}

/**
* Uses <input type="text"> elements when rendering this field in forms
*/
public function renderAsText(bool $asText = true): self
{
if (false === $asText) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_TEXT);
}

return $this;
}
}
46 changes: 45 additions & 1 deletion src/Field/TimeField.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class TimeField implements FieldInterface
use FieldTrait;

public const OPTION_TIME_PATTERN = 'timePattern';
public const OPTION_WIDGET = 'widget';

public static function new(string $propertyName, ?string $label = null): self
{
Expand All @@ -24,7 +25,8 @@ public static function new(string $propertyName, ?string $label = null): self
->addCssClass('field-time')
// the proper default values of these options are set on the Crud class
->setCustomOption(self::OPTION_TIME_PATTERN, null)
->setCustomOption(DateTimeField::OPTION_TIMEZONE, null);
->setCustomOption(DateTimeField::OPTION_TIMEZONE, null)
->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
}

/**
Expand Down Expand Up @@ -59,4 +61,46 @@ public function setFormat(string $timeFormatOrPattern): self

return $this;
}

/**
* Uses native HTML5 widgets when rendering this field in forms
*/
public function renderAsNativeWidget(bool $asNative = true): self
{
if (false === $asNative) {
$this->renderAsChoice();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
}

return $this;
}

/**
* Uses <select> lists when rendering this field in forms
*/
public function renderAsChoice(bool $asChoice = true): self
{
if (false === $asChoice) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_CHOICE);
}

return $this;
}

/**
* Uses <input type="text"> elements when rendering this field in forms
*/
public function renderAsText(bool $asText = true): self
{
if (false === $asText) {
$this->renderAsNativeWidget();
} else {
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_TEXT);
}

return $this;
}
}
2 changes: 1 addition & 1 deletion src/Resources/public/app.css

Large diffs are not rendered by default.

0 comments on commit 6d0170d

Please sign in to comment.