I want to use MudDatePicker element in a way where I need to be able to set a default value on load but at the same time define a onChange event for it. I am trying to do this but error says "The component parameter is used two or more times for this component". Is there a way I can do this?
<MudDatePicker #bind-Date="#DefaultValue.Value" Label="Date" DateChanged="OnDateChange"
Required="true" Class="mb-3" />
If you have a two-way binding in Blazor i.e. #bind-Date="date", you can convert it to a one-way binding with a change event which must set the value. The two-way binding is just syntax sugar and will do the same behind the scene.
<MudDatePicker Date="#_date" Label="Date" DateChanged="OnDateChange"
Required="true" Class="mb-3" />
#inject ISnackbar Snackbar
#code {
DateTime? _date = new DateTime(2021, 12, 24);
void OnDateChange(DateTime? newDate)
{
_date=newDate;
// here you can do something when the date changes.
Snackbar.Add($"Date changed to {_date}");
}
}
Here is a snippet which you can play around with: https://try.mudblazor.com/snippet/mYcPFPvLnlyEHeOF
Remove the DateChanged="OnDateChange" and change #bind-Date="DefaultValue.Value" to #bind-Date="DefaultValue". For the property DefaultValue create a getter and setter. Because you have two way binding using #bind-Date="DefaultValue", the setter part gets called every time the value is changed.
I've added some sample code below:
DateTime? _defaultValue = DateTime.Now;
private DateTime? DefaultValue
{
get => _defaultValue;
set
{
_defaultValue = value;
OnDateChange();
}
}
Related
I have a problem with a p:selectOneMenu, no matter what I do I cannot get JSF to call the setter on the JPA entity. JSF validation fails with this message:
form:location: Validation Error: Value is not valid
I have this working on several other class of the same type (ie, join table classes) but cannot for the life of me get this one working.
If anyone can throw some troubleshooting/debugging tips for this sort of problem it would be greatly appreciated.
Using log statements I have verified the following:
The Conveter is returning correct, non null values.
I have no Bean Validation in my JPA entities.
The setter setLocation(Location location) is never called.
This is the simplest example I can do and it simply will not work:
<h:body>
<h:form id="form">
<p:messages id="messages" autoUpdate="true" />
<p:selectOneMenu id="location" value="#{locationStockList.selected.location}" converter="locationConverter">
<p:ajax event="change" update=":form:lblLocation"/>
<f:selectItems value="#{locationStockList.locationSelection}"/>
</p:selectOneMenu>
</h:form>
</h:body>
Converter:
#FacesConverter(forClass=Location.class, value="locationConverter")
public class LocationConverter implements Converter, Serializable {
private static final Logger logger = Logger.getLogger(LocationConverter.class.getName());
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value.isEmpty())
return null;
try {
Long id = Long.parseLong(value);
Location location = ((LocationManagedBean) context.getApplication().getELResolver().getValue(context.getELContext(), null, "location")).find(id);
logger.log(Level.SEVERE, "Converted {0} to {1}" , new Object[] {value, location});
return location;
} catch (NumberFormatException e) {
return new Location();
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.toString().isEmpty() || !(value instanceof Location))
return "";
return String.valueOf(((Location) value).getId());
}
}
Console output:
// Getter method
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0]
// Session Bean
INFO: Finding ejb.locations.Location with id=3
// Session Bean
INFO: ### Returning : ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3]
// Converter
SEVERE: Converted 3 to ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3]
// Getter method -> Where did my selected Location go ??
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0]
Validation fails with the message "form:location: Validation Error: Value is not valid"
This error boils down to that the selected item does not match any of the available select item values specified by any nested <f:selectItem(s)> tag during processing of the form submit request.
As part of safeguard against tampered/hacked requests, JSF will reiterate over all available select item values and test if selectedItem.equals(availableItem) returns true for at least one available item value. If no one item value matches, then you'll get exactly this validation error.
This process is under the covers basically as below, whereby bean.getAvailableItems() fictionally represents the entire list of available select items as defined by <f:selectItem(s)>:
String submittedValue = request.getParameter(component.getClientId());
Converter converter = component.getConverter();
Object selectedItem = (converter != null) ? converter.getAsObject(context, component, submittedValue) : submittedValue;
boolean valid = false;
for (Object availableItem : bean.getAvailableItems()) {
if (selectedItem.equals(availableItem)) {
valid = true;
break;
}
}
if (!valid) {
throw new ValidatorException("Validation Error: Value is not valid");
}
So, based on the above logic, this problem can logically have at least the following causes:
The selected item is missing in the list of available items.
The equals() method of the class representing the selected item is missing or broken.
If a custom Converter is involved, then it has returned the wrong object in getAsObject(). Perhaps it's even null.
To solve it:
Ensure that exactly the same list is been preserved during the subsequent request, particularly in case of multiple cascading menus. Making the bean #ViewScoped instead of #RequestScoped should fix it in most cases. Also make sure that you don't perform the business logic in the getter method of <f:selectItem(s)>, but instead in #PostConstruct or an action event (listener) method. If you're relying on specific request parameters, then you'd need to explicitly store them in the #ViewScoped bean, or to re-pass them on subsequent requests by e.g. <f:param>. See also How to choose the right bean scope?
Ensure that the equals() method is implemented right. This is already done right on standard Java types such as java.lang.String, java.lang.Number, etc, but not necessarily on custom objects/beans/entites. See also Right way to implement equals contract. In case you're already using String, make sure that the request character encoding is configured right. If it contains special characters and JSF is configured to render the output as UTF-8 but interpret the input as e.g. ISO-8859-1, then it will fail. See also a.o. Unicode input retrieved via PrimeFaces input components become corrupted.
Debug/log the actions of your custom Converter and fix it accordingly. For guidelines, see also Conversion Error setting value for 'null Converter' In case you're using java.util.Date as available items with <f:convertDateTime>, make sure that you don't forget the full time part in the pattern. See also "Validation Error: Value is not valid" error from f:datetimeConverter.
See also:
Our selectOneMenu wiki page
How to populate options of h:selectOneMenu from database?
Make multiple dependent / cascading selectOneMenu dropdown lists in JSF
If anyone can throw some troubleshooting/debugging tips for this sort of problem it would be greatly appreciated.
Just ask a clear and concrete question here. Do not ask too broad questions ;)
In my case I forgot to implement a correct get/set methods. It happened because I have changed a lot of attributes along the development.
Without a proper get method, JSF can´t recover your selected item, and happens what BalusC said at item 1 of his answer:
1 . The selected item is missing in the list of available items. This can happen if the list of available items is served by a request scoped bean which is not properly reinitialized on subsequent request, or is incorrectly doing the business job inside a getter method which causes it to return a different list in some way.
This can be a Converter Issue or else DTO issue.
Try to solve this, by adding hashCode() and equals() methods in your object DTO; In the above scenario you can generate these methods within the Location object class which indicate as the 'DTO' here.
Example:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Location other = (Location) obj;
if (id != other.id)
return false;
return true;
}
Please note that the above example is for an 'id' of type 'long'.
I am having some trouble implementing an ajax listener event which detects when a date is changed on a form. I have a datatable and inside one of the columns I have an <ace:dateTimeEntry> which holds a start date field which is stored in the bean. (Note: alliance is the name of the variable used for the datatable).
<ace:column headerText="Start Date" rendered="#{not alliance.deletePending}">
<ace:dateTimeEntry id="startDateField" value="#{alliance.allianceStartDate}" pattern="dd/MMM/yyyy" renderAsPopup="true" effect="fadeIn">
<ace:ajax execute="#this" render="#this" event="dateSelect" listener="#{allianceViewBean.changeAllianceActiveIndicator}"/>
<ace:ajax execute="#this" render="#this" event="dateTextChange" listener="#{allianceViewBean.changeAllianceActiveIndicator}"/>
</ace:dateTimeEntry>
</ace:column>
I am using an tag which calls a listener method in the bean called
#{allianceViewBean.changeAllianceActiveIndicator}
This is the bean value change method:
public void changeAllianceActiveIndicator(AjaxBehaviorEvent event) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
java.util.Date currentDate = c.getTime();
for (AllianceBean bean : carrierAllianceDetails) {
if ((bean.getAllianceStartDate().compareTo(currentDate) < 0)
&& (bean.getAllianceEndDate().compareTo(currentDate) > 0)) {
bean.setActive(true);
} else {
bean.setActive(false);
}
}
}
However, when I debug this method errors occur. The listener correctly reaches the method but the start date value in the bean is not the updated value and it still refers to the old value before the change. If i enter a new value on the form, the value in the bean is always referring to the previously entered date value. The logic is correct in the method but the values being checked are not.
I am not sure how to ensure that the listener method picks up the latest value from the form.
Thanks
This is due to the lifecycle phase you are in. Check the lifecycle phase in which this event comes in. If it is before the UPDATE_MODEL_VALUES phase (e.g. in the PROCESS_VALIDATIONS phase) then your bean values are simply not updated yet. In that case I would recommend to set the phaseId to INVOKE_APPLICATION on the event, queue it and return the method:
public void changeAllianceActiveIndicator(AjaxBehaviorEvent event) {
if (!event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
java.util.Date currentDate = c.getTime();
for (AllianceBean bean : carrierAllianceDetails) {
if ((bean.getAllianceStartDate().compareTo(currentDate) < 0)
&& (bean.getAllianceEndDate().compareTo(currentDate) > 0)) {
bean.setActive(true);
} else {
bean.setActive(false);
}
}
}
Apart from that the code of your method is not ideal either. Setting the default timeZone is pretty obsolete - as well the whole Calendar block. You could just do
Date currentDate = new Date();
I would also recommend to convert the date that is set on the bean to the server timeZone's date - otherwise you are comparing apples and oranges.
I'm trying to set the date of birth of a person using jQuery Datepicker. However, all I get is that the Property dateOfBirth must be a valid Date.
So, originally, my controller looks like this:
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
I figured out, that with jQuery I should use a SimpleDateFormat object in order to generate a proper Date object. Nevertheless, even if I directly assign a new Date object to dateOfBirth and subsequently validating the personInstance domain object - like in the following code segment - I still get the Property dateOfBirth must be a valid Date error.
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
// added code
personInstance.dateOfBirth = new Date()
personInstance.validate()
// added code
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
Thank you for any help :)
The reason why you are still seeing errors is because validation is automatically called after binding your command/domain object when the method is called.
Use personInstance.clearErrors() before calling personInstance.validate() manually to clear out any existing binding/validation errors. You can see more about this in the documentation.
I use the following jQuery function to format my datepicker
$(".datepicker").datepicker({
dateFormat : "MM yy"
}).attr('readonly', true);
Upon selection I can see the text field is set correctly to November 2013. Before form is submitted I am using Spring validation to validate the date with
public class LocalMonthEditor extends PropertyEditorSupport {
#Override
public void setAsText(final String text) throws IllegalArgumentException {
if (!StringUtils.hasText(text)) {
// Treat empty String as null value.
setValue(null);
} else {
LocalDateTime localDateTime = LocalDateTime.parse(text,
DateTimeFormat.forPattern("MMMM yyyy"));
setValue(localDateTime);
}
}
#Override
public void setValue(final Object value) {
super.setValue(value == null || value instanceof LocalDateTime ? value
: new LocalDateTime(value));
}
#Override
public LocalDateTime getValue() {
return (LocalDateTime) super.getValue();
}
#Override
public String getAsText() {
return getValue() != null ? getValue().toString() : "";
}
}
However after form being submitted the text field is changed to 2013-11-01T00:00:00.000. How can I maintain the field to November 2013 ?
First of all, if the data you need is simply a month and a year, why are you using Joda-Time at all? That's like getting in your car to drive to your mailbox at the end of the driveway: extra effort and complexity for no benefit.
Instead, I suggest you choose between:
Track a pair of variables (month, year)
Define your own class with a pair of members (month, year), and track an instance.
Use a String as seems to be your intention: "November 2013" as you seem to be thinking, or a simpler schemes such as "2013-11".
Secondly, because you created an instance of LocalDatetime, at some point toString seems to be called. The default output of toString on a LocalDateTime is output in the standard ISO 8601 format you saw: 2013-11-01T00:00:00.000. A LocalDateTime has a date value and a time value (hence the name), even if the time value may be set to zeros (meaning start of day). So this is a feature, not a bug.
I don't know Spring Validatation nor the rest of your class structure. I'm guessing you are storing a LocalDateTime instance where instead you meant to be (or should be) storing a String instance. You may need to read up on the subject of "model" versus "view". Often we track data behind the scenes differently than we present data to the user. In this case, you probably should be holding a pair of ints or Integers (one for month, one for year) in your model with a String in your view ("November 2013").
You are setting your local time object directly to text field, thats why your getting full date string.convert your date object by using parse() method and set it. Do not create new object for date set your value directly.
This question already has an answer here:
"Validation Error: Value is not valid" error from f:datetimeConverter
(1 answer)
Closed 6 years ago.
I have a problem mentioned in the topic. I have
<h:selectOneMenu class="time" id="time" value="#{auctionBean.expDate}">
<f:convertDateTime pattern="dd/MM/yyyy HH:mm:ss"/>
<f:selectItem itemValue="11/11/1111 11:11:11" itemLabel="1 day" />
<f:selectItem itemValue="#{auctionBean.calculateExpDate(4)}" itemLabel="4 days" />
<f:selectItem itemValue="#{auctionBean.calculateExpDate(7)}" itemLabel="7 days" />
<f:selectItem itemValue="#{auctionBean.calculateExpDate(14)}" itemLabel="14 days" />
</h:selectOneMenu>
The problem is i am getting Validation Error: Value is not valid message for all items but first one.
The method:
public String calculateExpDate(int days) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, days);
Format formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
System.out.println("data: " + formatter.format(cal.getTime()));
return formatter.format(cal.getTime());
}
It returns String in good format. Output from system.out:
INFO: data: 10/10/2013 20:40:04
Where is the problem? I have no clue at all
A good one!
If what you are getting is a VALIDATION error, not a CONVERSION problem, then the probable scenario is:
the list of available values is created, and the values have precision of 1 second,
user picks one of them,
but on postback the available values get recalculated, and they are all a couple of seconds later than the original ones.
so the value that your user picked is no more available on the list of possible values,
and so a validation error happens (which is what JSF does always when the value chosen is no longer on the list of select items).
you do not get it with the first item, because it's the only one that does not change with time :-).
If you move the backing bean to view scope (or session scope), or cut the precision, it should work. Or better yet - make an enum with values of NOW, IN_2_DAYS, IN_4_DAYS and so on. And calculate the real date after the enum is chosen.
fdreger is right! I marked his post as an answer. Thanks:)
This is my solution if you are lazy (however it might be done better I guess):
JSF:
<h:selectOneMenu class="time" id="time" value="#{auctionBean.choosenOption}">
<f:selectItems value="#{auctionBean.days}" var="days" itemValue="#{days}" itemLabel="#{days.label}"/>
</h:selectOneMenu>
fragment of my auctionBean:
public enum Days {
IN_1_DAY("1 dzień", 1),
IN_4_DAYS("4 dni", 4),
IN_7_DAYS("7 dni", 7),
IN_14_DAYS("14 dni", 14);
private String label;
private int days;
private Days(String label, int days) {
this.label = label;
this.days = days;
}
public String getLabel() {
return label;
}
public Date calculateExpDate() {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, this.days);
return cal.getTime();
}
}
private Days choosenOption;
public void setChoosenOption(Days choosenOption) {
this.choosenOption = choosenOption;
expDate = choosenOption.calculateExpDate();
}
public Days getChoosenOption() {
return choosenOption;
}
public Days[] getDays() {
return Days.values();
}
User chooses how many days his auction should be active and i calculate what is an expiration date.
expDate is Date object which i set only once, after choosing the single enum and sumbitting the form. Pretty good solution suggested :)