User tests: Successful: Unsuccessful:
Pull Request resolves #48416.
FormField::getLayoutData() already exposes $validationtext (populated from the XML validationtext attribute) to every field layout under layouts/joomla/form/field/. But of the 36 files there, only text.php actually turns it into the data-validation-text HTML attribute that validate.es6.js's markInvalid() reads for the client-side "invalid" message — and even there it is marked // @TODO add a proper string here!!!. checkbox.php documents $validationtext in its docblock but never uses it. Every other field type — including several that already build their own pattern attribute for HTML5 validation (tel, date, datetime, email, url, number, ...) — has no reference to it at all.
This PR moves the translate-and-output step into FormField::renderDataAttributes(), the shared method that builds $dataAttribute and is already echoed by essentially every field layout. That makes validationtext work consistently for all field types from one place, with consistent escaping: the current text.php uses $this->escape(), while several other layouts build their data attributes via ArrayHelper::toString(), which does not escape at all. renderDataAttributes() already uses htmlspecialchars(), so centralizing here avoids that inconsistency.
The now-redundant line in text.php is removed, which also resolves its @TODO.
Backward compatibility: a field that already sets a literal data-validation-text="..." XML attribute is unaffected — the new code only fills the key when it is not already present.
Client-side validation only shows a message when a field is actually invalid at the moment you click Save. So each test below makes the field invalid on purpose. Use a literal (untranslated) validationtext string so it is obvious where the message comes from: Text::_() returns an unknown key unchanged.
The message is shown inside the field's label (a red span.form-control-feedback), not under the input. A red alert at the top of the page also says that the form can't be submitted.
Log in as a Super User so no field is disabled (disabled fields are skipped by the validator).
email field (most reliable)administrator/components/com_contact/forms/contact.xml and add a validationtext to the email_to field: <field
name="email_to"
type="email"
label="JGLOBAL_EMAIL"
validate="email"
validationtext="Custom message: please enter a valid e-mail address"
/>data-validation-text="Custom message: please enter a valid e-mail address".not-an-email in the E-mail field and click Save.calendar fieldadministrator/components/com_content/forms/article.xml and change the publish_up field. Adding required="true" is essential, because the core field is optional and an empty value would otherwise simply be valid: <field
name="publish_up"
type="calendar"
label="COM_CONTENT_FIELD_PUBLISH_UP_LABEL"
translateformat="true"
showtime="true"
filter="user_utc"
required="true"
validationtext="Custom message: a start publishing date is required"
/>data-validation-text attribute and class="form-control required".textarticle.xml, add validationtext="Custom message: title is required" to the title field (already required="true").data-validation-text still winsemail_to field from test 1, also add data-validation-text="Explicit attribute wins".validationtext value.data-validation-text attribute. On Save the label shows the generic message ("This value is not valid" for the e-mail, "Please fill in this field" for the calendar). The validationtext value is silently ignored. The same applies to every field type except text.data-validation-text="…", and on Save the custom message is shown in the label.data-validation-text is kept.Please select:
Documentation link for guide.joomla.org:
No documentation changes for guide.joomla.org needed
Pull Request link for manual.joomla.org:
No documentation changes for manual.joomla.org needed
| Status | New | ⇒ | Pending |
| Category | ⇒ | Layout Libraries |
@hans2103 Please keep the structure of the description of this PR like in our pull request template, and acknowledge the Generative AI policy . Thanks in advance.
@richard67 body text adjusted to the template
| Labels |
Added:
PR-5.4-dev
|
||
I have tested this item ✅ successfully on 21c9140
I tested this with several different types of fields - text, integer, number (float), list.
The number field had custom client-side validation and when invalid data was entered the validationtext language string was correctly translated and output.
For the other fields I verified that the data-validation-text attribute was set from the validationtext attribute.
If both validationtext and data-validation-text attributes are set then the data-validation-text attribute takes precedence (correct behaviour, in my view).
I have tested this item ✅ successfully on 21c9140
I tested this with several different types of fields - text, integer, number (float), list.
The number field had custom client-side validation and when invalid data was entered the validationtext language string was correctly translated and output.
For the other fields I verified that the data-validation-text attribute was set from the validationtext attribute.
If both validationtext and data-validation-text attributes are set then the data-validation-text attribute takes precedence (correct behaviour, in my view).
| Title |
|
||||||
As 5.4 has reached end of bugfix support and is now in security only support mode, I've allowed myself to rebase this PR here to 6.2-dev, where bug fixes should be made now. This worked cleanly, so the previous human test is still valid.
| Labels |
Added:
bug
PR-6.2-dev
Removed: PR-5.4-dev |
||
validationtext="MY_VALIDATION_MESSAGE"
data-validation-text=""
The explicitly supplied empty attribute takes precedence, because isset() returns true for an empty string.
That is arguably correct because an explicitly supplied value should take precedence. However, it is worth considering whether an empty attribute should instead allow the translated validationtext value to be used.
@brianteeman thx
An empty data-validation-text isn’t a meaningful override: markInvalid() treats "" as a custom message (message !== null), so the field would show an empty feedback span instead of the default text. I’ve changed the check from isset() to empty(), so an empty attribute now falls back to the translated validationtext, while a non-empty explicit attribute still takes precedence.
Test 4 in the description now covers both cases.
@brianteeman The empty() check didn't help either.
FormField::setup() stores data-* XML attributes as SimpleXMLElement objects, not as strings. empty() never considers an object empty, even when the attribute value is "". I verified this against the real FormField::setup():
| XML | Stored as | empty() |
trim((string) …) === '' |
|---|---|---|---|
data-validation-text="" |
SimpleXMLElement object |
false ❌ | true ✅ |
| no attribute | – | true | true ✅ |
data-validation-text="Explicit" |
SimpleXMLElement object |
false | false ✅ |
The check now casts the value to string before comparing:
if (!empty($this->validationtext) && trim((string) ($dataAttributes['data-validation-text'] ?? '')) === '') {
$dataAttributes['data-validation-text'] = Text::_($this->validationtext);
}I have tested this item ✅ successfully on 9579744
I have tested this item ✅ successfully on 9579744
@robbiejackson would you be so kind to test again? I have added a fix which results in a reset of the Human Tests.
With a successful test of yours we're back on 2
I have tested this item ✅ successfully on 9579744
I repeated the tests, and confirm that validationtext overrides data-validation-text only if data-validation-text is an empty string, or just contains white space.
I have tested this item ✅ successfully on 9579744
I repeated the tests, and confirm that validationtext overrides data-validation-text only if data-validation-text is an empty string, or just contains white space.
| Status | Pending | ⇒ | Ready to Commit |
RTC
RTC
| Labels |
Added:
RTC
|
||
@hans2103 - Thank you for the PR - it looks good, but does not cover "every form field type" - date.php and datetime.php (and also color/simple.php) do not output $dataAttribute. A required field left empty would therefore still ignore validationtext. Could you include these layouts too? Otherwise you may need to change the title of the PR ;-)
This PR here is for the 5.4-dev branch, so it should be tested on 5.4.