Skip to content

Commit 6d0170d

Browse files
committed
feature #3530 Render date and time fields using native form widgets by 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
2 parents f4f56e2 + 464f59c commit 6d0170d

File tree

6 files changed

+159
-4
lines changed

6 files changed

+159
-4
lines changed

assets/css/easyadmin-theme/fields.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@
122122
text-transform: uppercase;
123123
}
124124

125+
// Date, Time and DateTime fields
126+
.field-datetime input[type="datetime-local"].form-control,
127+
.field-date input[type="date"].form-control,
128+
.field-time input[type="time"].form-control {
129+
width: auto;
130+
}
131+
125132
// Language field
126133
.field-language .badge-language {
127134
border: 2px solid var(--gray-300);

src/Field/Configurator/DateTimeConfigurator.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
5151
$formattedValue = $this->intlFormatter->formatTime($field->getValue(), null, $timePattern, $timezone);
5252
}
5353

54+
$widgetOption = $field->getCustomOption(DateTimeField::OPTION_WIDGET);
55+
if (DateTimeField::WIDGET_NATIVE === $widgetOption) {
56+
$field->setFormTypeOption('widget', 'single_text');
57+
$field->setFormTypeOption('html5', true);
58+
} elseif(DateTimeField::WIDGET_CHOICE === $widgetOption) {
59+
$field->setFormTypeOption('widget', 'choice');
60+
$field->setFormTypeOption('html5', true);
61+
} elseif(DateTimeField::WIDGET_TEXT === $widgetOption) {
62+
$field->setFormTypeOption('widget', 'single_text');
63+
$field->setFormTypeOption('html5', false);
64+
}
65+
5466
$field->setFormattedValue($formattedValue);
5567

5668
$doctrineDataType = $entityDto->getPropertyMetadata($field->getProperty())->get('type');

src/Field/DateField.php

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ final class DateField implements FieldInterface
1313
use FieldTrait;
1414

1515
public const OPTION_DATE_PATTERN = 'datePattern';
16+
public const OPTION_WIDGET = 'widget';
1617

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

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

6062
return $this;
6163
}
64+
65+
/**
66+
* Uses native HTML5 widgets when rendering this field in forms
67+
*/
68+
public function renderAsNativeWidget(bool $asNative = true): self
69+
{
70+
if (false === $asNative) {
71+
$this->renderAsChoice();
72+
} else {
73+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
74+
}
75+
76+
return $this;
77+
}
78+
79+
/**
80+
* Uses <select> lists when rendering this field in forms
81+
*/
82+
public function renderAsChoice(bool $asChoice = true): self
83+
{
84+
if (false === $asChoice) {
85+
$this->renderAsNativeWidget();
86+
} else {
87+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_CHOICE);
88+
}
89+
90+
return $this;
91+
}
92+
93+
/**
94+
* Uses <input type="text"> elements when rendering this field in forms
95+
*/
96+
public function renderAsText(bool $asText = true): self
97+
{
98+
if (false === $asText) {
99+
$this->renderAsNativeWidget();
100+
} else {
101+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_TEXT);
102+
}
103+
104+
return $this;
105+
}
62106
}

src/Field/DateTimeField.php

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,13 @@ final class DateTimeField implements FieldInterface
3636
self::FORMAT_NONE => '',
3737
];
3838

39+
public const WIDGET_NATIVE = 'native';
40+
public const WIDGET_CHOICE = 'choice';
41+
public const WIDGET_TEXT = 'text';
42+
3943
public const OPTION_DATETIME_PATTERN = 'dateTimePattern';
4044
public const OPTION_TIMEZONE = 'timezone';
45+
public const OPTION_WIDGET = 'widget';
4146

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

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

105111
return $this;
106112
}
113+
114+
/**
115+
* Uses native HTML5 widgets when rendering this field in forms
116+
*/
117+
public function renderAsNativeWidget(bool $asNative = true): self
118+
{
119+
if (false === $asNative) {
120+
$this->renderAsChoice();
121+
} else {
122+
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_NATIVE);
123+
}
124+
125+
return $this;
126+
}
127+
128+
/**
129+
* Uses <select> lists when rendering this field in forms
130+
*/
131+
public function renderAsChoice(bool $asChoice = true): self
132+
{
133+
if (false === $asChoice) {
134+
$this->renderAsNativeWidget();
135+
} else {
136+
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_CHOICE);
137+
}
138+
139+
return $this;
140+
}
141+
142+
/**
143+
* Uses <input type="text"> elements when rendering this field in forms
144+
*/
145+
public function renderAsText(bool $asText = true): self
146+
{
147+
if (false === $asText) {
148+
$this->renderAsNativeWidget();
149+
} else {
150+
$this->setCustomOption(self::OPTION_WIDGET, self::WIDGET_TEXT);
151+
}
152+
153+
return $this;
154+
}
107155
}

src/Field/TimeField.php

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ final class TimeField implements FieldInterface
1313
use FieldTrait;
1414

1515
public const OPTION_TIME_PATTERN = 'timePattern';
16+
public const OPTION_WIDGET = 'widget';
1617

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

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

6062
return $this;
6163
}
64+
65+
/**
66+
* Uses native HTML5 widgets when rendering this field in forms
67+
*/
68+
public function renderAsNativeWidget(bool $asNative = true): self
69+
{
70+
if (false === $asNative) {
71+
$this->renderAsChoice();
72+
} else {
73+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_NATIVE);
74+
}
75+
76+
return $this;
77+
}
78+
79+
/**
80+
* Uses <select> lists when rendering this field in forms
81+
*/
82+
public function renderAsChoice(bool $asChoice = true): self
83+
{
84+
if (false === $asChoice) {
85+
$this->renderAsNativeWidget();
86+
} else {
87+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_CHOICE);
88+
}
89+
90+
return $this;
91+
}
92+
93+
/**
94+
* Uses <input type="text"> elements when rendering this field in forms
95+
*/
96+
public function renderAsText(bool $asText = true): self
97+
{
98+
if (false === $asText) {
99+
$this->renderAsNativeWidget();
100+
} else {
101+
$this->setCustomOption(self::OPTION_WIDGET, DateTimeField::WIDGET_TEXT);
102+
}
103+
104+
return $this;
105+
}
62106
}

src/Resources/public/app.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)