Conditional Expression (docs):
<tr th:class="${row.even}? 'even' : 'odd'">
I want to use conditional expression within a th:field. But every time I try it I get the following error:
*only variable expressions ${...} or selection expressions {...} are allowed in Spring field bindings
For example:
// This works fine.
<input type="text" th:value="${object.covered} ? 'yes' : 'no'" />
// This on the other hand, generates the error mentioned earlier.
// Which does make sense, cause it would otherwise generate invalid attributes.
<input type="text" th:field="${object.covered} ? 'yes' : 'no'" />
// Combining the two does not work.
<input type="text" th:field="${object.covered}" th:value="${object.covered} ? 'yes' : 'no'" />
Basically, what I want, is to create a th:field where its value is determined by a conditional expression.
More specific, In my implementation I want to populate a input field with a number (Java long) from my model. And if that number is zero or lesss, I want to use a placeholder instead.
// Ultimateley, what I want to achieve is something like this.
<input type="text" th:field="${person.age}"
th:value="${person.age} le 0 ? null : ${person.age}"
placeholder="age" />
How to use th:field, and determine its value with a conditional expression with Spring Thymeleaf?
(Thymeleaf 2.1.5, and Spring Boot 1.4.2)
Thymeleaf th:field generates 3 html attributes id, name an value.
For your case, instead of using th:field, use id, name and placeholder when age is less than zero, as shown below
<input th:if="${person.age > 0}" type="text" th:field="${person.age}" />
<input th:if="${person.age <= 0}" type="text" id="person.age" name="person.age" placeholder="age"/>
Related
I'm using vee-validate form validation and I have 3 address fields:
House Number
House Name
Flat Number
All 3 are optional because an address may only have 1, but I need the user to fill in at least one. So I can't make any of them required, and the documentation for cross field validation only handles putting specific validation on a single or multiple fields:
https://logaretm.github.io/vee-validate/advanced/cross-field-validation.html#targeting-other-fields
What is the best way of handling this? I'm no stranger to custom validation rules in my project, I just don't understand the approach here.
Thanks.
<div class="flex flex-wrap pb-2">
<FormTextInput
name="addressBuildingNo"
v-model="value.buildingNo"
type="text"
:label="$t('formFields.addressBuildingNo')"
placeholder="e.g 10"
:hint="$t('formHints.optional')"
/>
<FormTextInput
name="addressFlatNo"
v-model="value.flatNo"
type="text"
:label="$t('formFields.addressFlatNo')"
:hint="$t('formHints.optional')"
/>
<FormTextInput
name="addressBuildingName"
v-model="value.buildingName"
type="text"
:label="$t('formFields.addressBuildingName')"
:hint="$t('formHints.optional')"
/>
</div>
Wrap each one in a ValidationProvider and set the required rule on each to be that it's required if neither of the other two are filled out. So the first one would look like this:
<ValidationProvider :rules="{ 'required': (!value.buildingName && !value.flatNo)">
<FormTextInput
name="addressBuildingNo"
v-model="value.buildingNo"
type="text"
:label="$t('formFields.addressBuildingNo')"
placeholder="e.g 10"
:hint="$t('formHints.optional')"
/>
</ValidationProvider>
If you want more complicated validation, you can also write cross-field validators for each one that check things more specifically (following the docs you pointed out already). See a simplified example here: https://codesandbox.io/s/veevalidate-30-cross-field-optional-3dzxd
In the end I just made a hidden field with the value being a combination of all 3 fields.
<FormTextInput name="addressBuilding" type="hidden" v-model="compBuildingValue" rules="required" />
compBuildingValue() {
return `${this.value.buildingNo.trim()}${this.value.flatNo.trim()}${this.value.buildingName.trim()}`
}
I used laravel validator.
I have a form wih 2 fields
If i fill one field "NAME" and i leave the other "SURNAME" empty pressing SAVE button of the form appears required alert message on SURNAME but the name inserted in the NAME field became empty! And i think form send data anyway.why?I aspect that form doesn't send datas
In the value attribute of each input you need to echo old("the-input-name") so it can retain the previous input before the error
<input name="name" value="{{old('name')}}" class="" />
You should use old('NAME') to get the value of the field after the validation fails, blade example:
<input type="text" value="{{ old('NAME') }}" />
An example In case of update forms you should display the original value from the database unless there's an error:
<input type="text" value="{{ old('NAME') ?? $your_entry->value }}" />
Take a look at the documentation for more details
Is there a way to use a fragment parameter in an expression?
I'd like to create a fragment to show fields with their corresponding binding errors e.g. like:
<div th:fragment="alert (field, fieldLabel)">
<label><span th:text="${fieldLabel}">Label:</span><input type="text" th:errorclass="field_error" th:field="*{field}"/></label>
<div th:if="${#fields.hasErrors(field)}"><span th:errors="*{field}">Some error</span></div>
</div>
Getting the fragment with:
<div th:replace=":: alert (field='firstName', fieldLabel='Firstname')">Field</div>
How do I use the field parameter in the expressions for the th:field and th:errors attributes? *{field} does at least not work.
With Thymeleaf 2.1 I've been using the following:
Declare field:
<input type="password" th:field="*{password}" />
Show possible errors related to password:
<div th:replace="util/form :: field-errors('password')"></div>
And this prints all the errors related to given field:
<div class="error-container help-block"
th:fragment="field-errors(field)"
th:if="${#fields.hasErrors('__${field}__')}">
<ul>
<li th:each="error : ${#fields.errors('__${field}__')}"
th:text="${error}" />
</ul>
</div>
It seems that it is not possible at least
using th:field and th:errors, it keeps trying to look for a bean instead
of the parameter of the fragment.
Try setting a local variable for the DOM object
th:with="variableName=${field}"
An then try to use that variable in the expressions.
I'm using Spring MVC and Spring Data and also have configured Spring Data's DomainClassConverter to automatically convert String id to the appropriate Domain class.
I'm now implementing a Order to Customer reference using the tag using:
<form:select path="customer">
<form:option value="" label="Select" />
<form:options items="${customers}" itemValue="id" />
</form:select>
which results in the given HTML:
<select id="customer" name="customer" class="span6">
<option value="">Select</option>
<option value="1">Customer A</option>
<option value="2">Customer B</option>
<option value="3">Customer C</option>
</select>
When submitting a post with e.g. Customer A selected I get a exception like:
org.apache.jasper.JasperException: org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type #javax.validation.constraints.NotNull #javax.persistence.ManyToOne nl.kapsalonreflection.domain.Customer for value ''; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: The given id must not be null!; nested exception is java.lang.IllegalArgumentException: The given id must not be null!
Which does not make sense at all as the value received should be 1 and not ''.
I also debugged the received request params and it only contained customer=1 (as expected)
Note that the InvalidDataAccessApiUsageException is coming from Spring Data's DomainClassConverter and if I remove the this converter the problem does not occur anymore.
I also debugged the DomainClassConverter and what I can see it tries to cover twice.
First with the String value 1 (as expected) but then another call with an empty String, causing the exception.
It get's weirder though...
When I replace <form:option value="" label="Select" /> with the plain html element <option value="">Select</option> then the exception does not occur, and hence only 1 call is made to the convert method with the String 1.
The weird part is that both <form:option value="" label="Select" /> and <option value="">Select</option> product the same html output...
I cannot explain the behaviour... although I seemm to have a 'workaround' with the plain html element I would like to know what is causing the issue.
Note that org.apache.jasper.JasperException indicates that exception occurs during JSP rendering, not during data binding. It's consistent with the fact that exception depends on <form:option value="" label="Select" /> - it's thrown when this tag is being processed when rendering the form after postback.
Behaviour you observe can be explained as follows: in order to determine its selected state <form:option> tries to compare its value with value of a field bound to <form:select>. If value of the bound field is null, <form:option> simply compares its value with null, that's why you don't get this exception during initial form rendering. Otherwise, <form:option> tries to convert its <value> to type of the bound field, and value = "" causes an exception at this step.
So, you should use null instead of empty string for "no option selected" value:
<form:option value="${null}" label="Select" />
You may need to consider attaching a propery editor in this kind of scenario, because if i see the code <form:options items="${customers}" itemValue="id" /> you are directly attaching the customers list to the options. I think its autmatically taking the toString and displaying the "Csutomer A", "Customer B" etc. Ideally you may need to use the itemLabel in the form:options tag or you may need to register a property editor and attach that in the initBinder http://static.springsource.org/spring/docs/2.5.x/reference/validation.html#beans-beans-conversion
How do I add HTML5 placeholder attributes to Spring webmvc's form:input, form:password and form:textarea elements?
As of Spring 3.0 form tags support dynamic attributes, therefore you can simply write
<form:input placeholder = "..." ... />
Regarding the new input types question - I had success by using spring bind and manually generating the input element. I'm using bootstrap so I already had a tag to wrap the control-group and apply the error message, but if you just want to inline it you can do the following.
if your path field was 'age', replace <form:input path="age"/> with
<spring:bind path="age">
<input id="age" name="age" type="number" value="${status.value}" />
</spring:bind>