Well. I find in all places and I still without solution. I need to do a input mask with Primefaces and bind the value to a Date object in my bean.
The problem is: I use a converter with all validations, convertions and formats with my own code. My answer is: Is other solution with better performance. I hope so. Please help.
P/D: I don't need use a pickdate. I need the input mask to do this
I use this:
<div style="margin-bottom:1em;font-size: 1.2em;">
<p:inputMask id="dob" mask="99/99/9999" value="#{viewMB.request.dateOfBirth}" style="width:8em;" >
<f:convertDateTime pattern="MM/dd/yyyy" />
</p:inputMask>
<p:watermark value="MM/DD/YYYY" for="dob" />
</div>
and you can still add custom validator if you wish.
Well, this is my solution
<h:form>
<p:inputMask mask="99-99-9999" value="#{mask.date}" converterMessage="Invalid Date!" converter="dateconverter" />
<h:commandButton actionListener="#{mask.submit()}" value="Submit" />
</h:form>
And the converter
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
System.out.println(value);
if (value != null) {
try {
if (validateDate(value)) {
return convertDate(value).toDate();
}
else{
throw new ConverterException("Invalid date!");
}
} catch (Exception e) {
throw new ConverterException("Invalid date!");
}
}
throw new ConverterException("Null String!");
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
System.out.println(value);
if (value != null) {
try {
Date now = (Date)value;
DateTime d = new DateTime(now);
return d.getDayOfMonth() + "-" + d.monthOfYear() + "-" + d.getYear();
} catch (Exception e) {
throw new ConverterException("Convertion failure!");
}
}
throw new ConverterException("Null object!");
}
private boolean validateDate(String param) throws ParseException{
//Param is a date format from input mask
String[] values = param.split("-");
int day = Integer.valueOf(values[0]);
int month = Integer.valueOf(values[1]);
int year = Integer.valueOf(values[2]);
DateTime converted = convertDate(param);
if (converted.getDayOfMonth() != day || converted.getMonthOfYear() != month || converted.getYear() != year) {
return false;
}
else{
return true;
}
}
private DateTime convertDate(String param) throws ParseException{
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Date convertedCurrentDate = sdf.parse(param);
return new DateTime(convertedCurrentDate);
}
The Managed Bean
#ManagedBean(name="mask")
public class MaskBean {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public void submit(){
RequestContext context = RequestContext.getCurrentInstance();
context.execute("alert('date submited: value recibed " + date.toString() + "')");
}
}
It work for me.
Related
I have a composite component made of two p:calendars:
<cc:interface componentType="testComponent">
<cc:attribute name="value" type="org.primefaces.test.DateRange" />
</cc:interface>
<cc:implementation>
<c:set value="dd-MM-yyyy" var="pattern" />
<p:panelGrid columns="2">
<p:outputLabel for="from" value="From" />
<p:calendar id="from" binding="#{cc.from}" pattern="#{pattern}" />
<p:outputLabel for="to" value="To" />
<p:calendar id="to" binding="#{cc.to}" pattern="#{pattern}" />
</p:panelGrid>
</cc:implementation>
Class DateRange:
public class DateRange {
private Date from;
private Date to;
public DateRange() {
}
public DateRange(Date from, Date to) {
this.from = from;
this.to = to;
}
public Date getFrom() {
return from;
}
public void setFrom(Date from) {
this.from = from;
}
public Date getTo() {
return to;
}
public void setTo(Date to) {
this.to = to;
}
#Override
public String toString() {
return from + " --> " + to;
}
}
Backing class:
#FacesComponent("testComponent")
public class TestComponent extends UIInput implements NamingContainer {
private UIInput from;
private UIInput to;
private static final String DELIMITER = "-->";
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
DateRange range = (DateRange) getValue();
System.out.println(range);
if (range != null) {
from.setValue(range.getFrom());
to.setValue(range.getTo());
}
super.encodeBegin(context);
}
#Override
public Object getSubmittedValue() {
if (from == null || to == null) return null;
String submittedFrom = (String) from.getSubmittedValue();
String submittedTo = (String) to.getSubmittedValue();
if (submittedFrom == null) {
submittedFrom = "";
}
if (submittedTo == null) {
submittedTo = "";
}
return submittedFrom + DELIMITER + submittedTo;
}
#Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) throws ConverterException {
String submitted = (String) newSubmittedValue;
if (submitted == null || submitted.isEmpty()) {
return null;
}
String[] split = submitted.split(DELIMITER);
String fromStr = split.length > 0 ? split[0] : "";
String toStr = split.length > 1 ? split[1] : "";
// TODO: Do I need to perform a manual conversion of the inputs???
return new DateRange((Date) fromObj, (Date) toObj);
}
getConvertedValue() should return an instance of DateRange. To get dates from calendars, I would need to call getConvertedValue() on each but this method is protected and I cannot access it.
Do I need to manually get the pattern from the p:calendar and convert the value myself? If yes, how do I even know how the conversion is really done in Calendaritself? I wonder how is this approached in more complex components where conversion on subcomponents is not that trivial.
I´m trying to use the Primefaces component: p:selectOneListbox
I would like to use the grouping function.
Currently I´m getting only a String instead the POJO. I´m already using a converter, but I don´t know what is currently wrong. If I´m returning only the List then it´s working fine and I´ve get the values as expected...
Here is my JSF code:
<p:selectOneListbox id="diagramElementList" value="#{myBean.selectedDiagramElementFromList}"
converter="diagramElementConverter" style="width: 100%"
var="diagramElement" filter="true" filterMatchMode="contains">
<f:selectItems
value="#{availableAutomationComponentControllerView.generateListAvailableElements()}"
var="diagramElement" itemLabel="#{diagramElement.name}"
itemValue="#{diagramElement}" />
<p:column style="width: 10px;">
<h:outputText value="#{diagramElement.icon}" />
</p:column>
Here my backend bean:
public List<SelectItem> generateListAvailableElements() {
try {
List<SelectItem> list = new ArrayList<SelectItem>();
SelectItemGroup g1 = new SelectItemGroup("Workflow");
List<DiagramElement> workflowList = automationElementService.generateListAvailableElements(
loginBean.getCurrentEmployee(), localeBean.getLanguage(),
AutomationElementCategory.WORKFLOW.toString());
g1.setSelectItems(createItemList(workflowList));
list.add(g1);
return list;
} catch (Exception e) {
LOGGER.error(ExceptionUtils.getFullStackTrace(e));
ErrorMessage.showErrorMessage();
}
return null;
}
private SelectItem[] createItemList(List<DiagramElement> list) {
List<SelectItem> newlist = new ArrayList<SelectItem>();
for (DiagramElement e : list) {
newlist.add(new SelectItem(e, e.getName()));
}
SelectItem[] arr = new SelectItem[newlist.size()];
arr = newlist.toArray(arr);
return arr;
}
And here my converter:
#FacesConverter("diagramElementConverter")
public class DiagramElementConverter implements Converter {
#Inject
private AutomationElementService automationElementService;
#Inject
private LoginBean loginBean;
#Inject
private LocaleBean localeBean;
public String getAsString(FacesContext context, UIComponent component, Object object) {
String field = (object instanceof DiagramElement) ? ((DiagramElement) object).getId() : null;
return (field != null) ? String.valueOf(field) : null;
}
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
try {
if (submittedValue == null) {
return null;
}
if (submittedValue.trim().equals("")) {
return null;
} else {
for (DiagramElement diagramElement : automationElementService.generateListAvailableElements(
loginBean.getCurrentEmployee(), localeBean.getLanguage(), null)) {
if (diagramElement.getId().equals(submittedValue)) {
return diagramElement;
}
}
}
} catch (Exception e) {
}
return null;
}
}
I have the datatable and selectonemenu inside it.
I want to show images in select one menu items.So a have Rating class and converter ratingConverter for Rating class.
I have the next problem here: filtering by this column works just once! When I try to change item, method load(..) from LazyComicsDataModel calls. But after
filtering one time nothing worked! Method load not calls anymore. There are't any exceptions in server.log. When I don't use converter and class Rating (use just String class) it works right any number of times.
I would like to get any ideas why it might be happened.
Code:
Part of xhtml page:
<p:ajax
event="rowSelect"
update=":form:comicsDetail"
oncomplete="PF('comicsDialog').show()"/>
<p:column width="20%"
headerText="#{comicsCatalogueView.columnComicsRating}"
sortBy="#{comics.rating}"
filterBy="#{comics.rating}"
filterMatchMode="exact" >
<f:facet name="filter" >
<p:selectOneMenu
value="#{comicsCatalogueView.rating}"
var="r"
onchange="PF('comicsTable').filter()"
converter="ratingConverter"
>
<f:selectItem
value="#{null}"
itemValue="#{null}" />
<f:selectItems
value="#{comicsFinderManagedBean.ratings}"
var="rating"
itemLabel="#{rating.value} - #{rating.value+1}"
itemValue="#{rating}"
/>
<p:column>
<p:graphicImage value="#{r.image}"/>
</p:column>
</p:selectOneMenu>
</f:facet>
<h:panelGroup>
<pf:rating disabled="true"
totalStars="5"
step="0.1"
value="#{comics.rating}"
>
</pf:rating>
</h:panelGroup>
</p:column>
Rating class:
public class Rating {
public Rating(Integer value, String image) {
this.value = value;
this.image = image;
}
private Integer value;
private String image;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
#Override
public int hashCode() {
int hash = 5;
hash = 71 * hash + (this.value != null ? this.value.hashCode() : 0);
hash = 71 * hash + (this.image != null ? this.image.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Rating other = (Rating) obj;
if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) {
return false;
}
if ((this.image == null) ? (other.image != null) : !this.image.equals(other.image)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Rating{" + "value=" + value + ", image=" + image + '}';
}
Rating converter:
#FacesConverter("ratingConverter")
public class RatingConverter implements Converter {
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
ComicsFinderManagedBean ratingFinderManagedBean = (ComicsFinderManagedBean)
fc.getExternalContext().getApplicationMap().get("comicsFinderManagedBean");
return ratingFinderManagedBean.getRating(Integer.parseInt(value));
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((Rating) object).getValue());
}
else {
return null;
}
}
}
I am selecting a date from a <p:calendar> component and I want to have the current time appended to the selected date.
Assume that now the time is 12/13/13 04:30:12 .
I had selected the date as 12/17/13 from the calendar and I want to save it as 12/17/13 04:30:12.
You can implement your custom #FacesConverter and apply it on the <p:calendar> component.
#FacesConverter("timestampConverter")
public class TimestampConverter implements Converter {
#Override
public Object getAsObject(FacesContext facesContext,
UIComponent uIComponent,
String string) {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");
Date date = null;
Calendar calendar = Calendar.getInstance();
try {
date = sdf.parse(string);
calendar.setTime(date);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY));
calendar.set(Calendar.MINUTE, now.get(Calendar.MINUTE));
calendar.set(Calendar.SECOND, now.get(Calendar.SECOND));
Timestamp result = new Timestamp(calendar.getTime().getTime());
return result;
}
#Override
public String getAsString(FacesContext facesContext,
UIComponent uIComponent,
Object object) {
if (object == null) {
return null;
}
return object.toString();
}
}
In the getAsObject(..) method you can get the String that's received from the front-end, append the current time and construct a Timestamp object as a result.
The snippet from the facelet (plus my testing button) looks like this:
<h:form>
<p:calendar value="#{myBean.date}" >
<f:converter converterId="timestampConverter" />
</p:calendar>
<p:commandButton title="Test" action="#{myBean.testAction}" />
<h:form>
and in the myBean class there should be a date property with the corresponding accessor methods.
#RequestScoped
#ManagedBean(name = "myBean")
public class MyBean {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
return date;
}
public String testAction() {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YY HH:mm:ss");
String output = sdf.format(date);
System.out.println("Selected date with timestamp: " + output);
}
}
More info:
JSF Custom Converter
I have a rich:pickList, when submit values it still displays error: "Validation Error: Value is not valid". I also set breakpoint to debug (getAsobject), but after system invocation I had nothing.
BalusC said that I would implement the equals() method in my entities, or I have the entities in the web service, and I fill the right side of the picklist with data from this web service.
xHTML file
<h:form>
<rich:panel>
<h:panelGrid columns="2" styleClass="criteresSaisie"
rowClasses="critereLigne" columnClasses="titreColonne,">
<h:outputLabel for="libelleComplement" value=" "
size="20" />
<rich:pickList id="libelleComplement" sourceCaption="Compléments"
targetCaption="Compléments sélectionnés"
value="#{listeCmpltDispoModel.listeCmpltSelect}" size="15"
addText=">" addAllText=">>" removeText="<"
removeAllText="<<" listWidth="270px" listHeight="110px"
orderable="true">
<f:selectItems value="#{listeCmpltDispoModel.listeCmpltDispo}"
var="liste" itemLabel="#{liste.libelleComplement}"
itemValue="#{liste}" />
<f:converter converterId="cmpltsTitresConcerter" />
</rich:pickList>
</h:panelGrid>
<h:panelGroup>
<div align="right">
<h:panelGrid columns="8">
<h:commandButton value="Valider"
action="#{saisieCmpltsTitreCtrl.valider}" />
</h:panelGrid>
</div>
</h:panelGroup>
</rich:panel>
</h:form>
Converter
#FacesConverter(value="cmpltsTitresConcerter")
public class CmpltsTitresConcerter implements Converter
{
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
ComplementsDispoSortieDTO cmpltSelect= new ComplementsDispoSortieDTO();
if(value != null)
{
cmpltSelect.setCdComplement(Long.parseLong(value));
//cmpltSelect.setLibelleComplement("aaa");
}
return cmpltSelect;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object obj)
{
String result = null;
if(obj != null)
{
result = String.valueOf(((ComplementsDispoSortieDTO) obj).getCdComplement());
}
return result;
}
}
Model
#ManagedBean(name = "listeCmpltDispoModel")
#SessionScoped
public class ListeCmpltDispoModel implements Serializable {
private static final long serialVersionUID = 1L;
private Long cdComplement;
private String libelleComplement;
private int nbCompl;
private List<ComplementsDispoSortieDTO> listeCmpltDispo ;
private List<ComplementsDispoSortieDTO> listeCmpltSelect ;
public ListeCmpltDispoModel() {
}
public Long getCodeComplement() {
return cdComplement;
}
public void setCodeComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement1() {
return libelleComplement;
}
public void setLibelleComplement1(String libelleCoplement) {
this.libelleComplement = libelleCoplement;
}
public Long getCdComplement() {
return cdComplement;
}
public void setCdComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement() {
return libelleComplement;
}
public void setLibelleComplement(String libelleComplement) {
this.libelleComplement = libelleComplement;
}
public List<ComplementsDispoSortieDTO> getListeCmpltDispo() {
return listeCmpltDispo;
}
public void setListeCmpltDispo(List<ComplementsDispoSortieDTO> listeCmpltDispo) {
this.listeCmpltDispo = listeCmpltDispo;
}
public int getNbCompl() {
return nbCompl;
}
public void setNbCompl(int nbCompl) {
this.nbCompl = nbCompl;
}
public List<ComplementsDispoSortieDTO> getListeCmpltSelect() {
return listeCmpltSelect;
}
public void setListeCmpltSelect(List<ComplementsDispoSortieDTO> listeCmpltSelect) {
this.listeCmpltSelect = listeCmpltSelect;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((cdComplement == null) ? 0 : cdComplement.hashCode());
result = prime
* result
+ ((libelleComplement == null) ? 0 : libelleComplement
.hashCode());
result = prime * result
+ ((listeCmpltDispo == null) ? 0 : listeCmpltDispo.hashCode());
result = prime
* result
+ ((listeCmpltSelect == null) ? 0 : listeCmpltSelect.hashCode());
result = prime * result + nbCompl;
return result;
}
#Override
public boolean equals(Object obj){
if(!(obj instanceof ComplementsDispoSortieDTO)){
return false;
}
return ((ComplementsDispoSortieDTO)obj).getCdComplement()==this.cdComplement;
}
}
The equals() method of your entity is not right. It's not only in the wrong class (the backing bean class instead of the model class), but it's also using == on an Object (the == on an object only tests the reference, not the internal value; as a starter, you should have experienced this mistake on String values already).
The == on a Long would only return true is the Long instance was created by Long#valueOf() or Long#parseLong() and the value is between -128 and 127. Anything else, including new Long(value) and those with values beyond the given "flyweight" range, return false.
As with every other Java object (such as your current one), you need equals() instead. Put it in the right class and implement it as follows:
public class ComplementsDispoSortieDTO {
private Long cdComplement;
// ...
#Override
public boolean equals(Object obj){
if (!(obj instanceof ComplementsDispoSortieDTO)){
return false;
}
return (cdComplement != null)
? cdComplement.equals(((ComplementsDispoSortieDTO) obj).cdComplement)
: (obj == this);
}
}
Note that I also added the missing reflexive obj == this. See also the javadoc for list of requirements.
See also:
Validation Error: Value is not valid
Right way to implement equals contract
I know which could be the solution.
You should store the list and selected element in properties and maintain them in the scope as long as the component is used.