Ajax not work on primefaces selectManyCheckbox with converter - ajax

I'm trying to use primefaces selectManyCheckBox with ajax and converter, but the ajax not fired. If I'm didn't use converter, the ajax can fired. Is there something wrong with my converter?
<div class="form-group">
<p:outputLabel value="Atur Grade Pinjaman" for="gradePinjaman"/>
<p:selectManyCheckbox id="gradePinjaman" value="#{autoInvestController.param.grades}" converter="companyGradeConverter">
<f:selectItems value="#{autoInvestController.grades}" var="grade" itemLabel="#{grade.id}" itemValue="#{grade}"/>
<p:ajax update="selectAll estimation" listener="#{autoInvestController.valueChange}"/>
</p:selectManyCheckbox>
<p:message for="gradePinjaman"/>
</div>
Here is my backing bean code
public void valueChange() {
if (param.getGrades() != null && !param.getGrades().isEmpty()) {
checkAll = param.getGrades().size() == grades.size();
calculateCollectEstimation();
}
}
Here is my converter
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (Strings.isNullOrEmpty(value)) {
return null;
} else {
try {
PlatformService platformService = (PlatformService) CDI.current().select(PlatformService.class).get();
Map<String, Object> param = new HashMap<>();
param.put("id", value);
CompanyGradeResponse companyGrade = platformService.getCompanyGrade(param).get(0);
return companyGrade;
} catch (EndpointException e) {
LOG.error(e.getMessage(), e);
return null;
}
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null) {
return ((CompanyGradeResponse) value).getId();
} else {
return null;
}
}
I think my converter work well, but why the ajax won't fired when i check the checkbox?
Thanks

Related

How to handle exceptions in a FacesConverter?

When the date format is not correct (for example when I manually post 13,02,2018 instead of 13.02.2018 and also other incorrect dates such as 13.02.999) the app crashes. How can I fix it? (the manual input is important, i can`t just disable it).
XHTML:
<rich:calendar enableManualInput="true" datePattern="dd.MM.yyyy"
value="#{myBean.data.myDate}">
<f:converter converterId="mydate"/>
</rich:calendar>
Converter:
#FacesConverter("mydate")
public class LocalDateConverter implements Converter {
private static final DateTimeFormatter formatter;
static {
formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
formatter.withLocale(new Locale("ru"));
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return LocalDate.parse(value, formatter);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
} else if (value instanceof LocalDate) {
return ((LocalDate) value).format(formatter);
} else if (value instanceof LocalDateTime) {
return ((LocalDateTime) value).format(formatter);
} else {
throw new IllegalArgumentException("Value is not java.time.LocaleDate");
}
}
Converters should throw a ConverterException which can contain a FacesMessage. This message can be displayed on your XHTML page, near the input component that caused the exception using <h:message for="inputComponentId"/>.
The problem occurs in your getAsObject method. There you should catch the DateTimeParseException exception and throw a ConverterException:
try {
return LocalDate.parse(value, formatter);
}
catch (DateTimeParseException ex) {
throw new ConverterException(new FacesMessage("Invalid date: " + value));
}
See also:
https://docs.oracle.com/javaee/7/tutorial/jsf-custom010.htm
How to use java.time.ZonedDateTime / LocalDateTime in p:calendar
You don't need converter at all. Simply include label attribute in rich:calendar component and let system figure out if value is correct. Example:
<h:outputLabel for="programStartDate" value="#{msg.programStartDate}" />
<rich:calendar id="programStartDate" value="#{program.programStartDate}"
label="#{msg.programStartDate}" inputStyle="width: 100px;"
datePattern="#{referenceData.defaultDatePattern}"
timeZone="#{referenceData.timezone}"
enableManualInput="true" popup="true" required="true" />
use a try catch and catch the exception so it doesn't crash but continue without allowing the exception to crash your program
#FacesConverter("mydate")
public class LocalDateConverter implements Converter
{
private static final DateTimeFormatter formatter;
static {
formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
formatter.withLocale(new Locale("ru"));
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
return LocalDate.parse(value, formatter);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
try
{
if (value == null)
{
return "";
}
else if (value instanceof LocalDate) {
return ((LocalDate)value).format(formatter);
} else if (value instanceof LocalDateTime) {
return ((LocalDateTime)value).format(formatter);
} else {
throw new IllegalArgumentException("Value is not java.time.LocaleDate");
}
}
catch (Exception)
{
return "SOME DEFAULT DATE";
}
}
}

JSF: Add AjaxBehaviour to dynamically generated HTMLInputText

I want to create UIComponents with an AjaxBehaviour dynamically and add it to a HTMLPanelGrid. The ajax method will be called but there was no value binding before and no rendering after that. Please help me! Thank you so much! Here is some code:
The Ajax function:
public void ajax(AjaxBehaviorEvent event) {
HtmlPanelGrid grid = (HtmlPanelGrid) event.getComponent().getParent();
HashMap<String, Object> params;
try {
ajaxSet(grid);
params = collect();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
SearchComponent search = (SearchComponent) ComponentRegistry.instance()
.getComponent(IComponentConstants.SEARCH);
this.score = Integer.toString(search.getSystemsCount(params));
}
The function for creating a HTMLInputText:
public HtmlInputText inputText(String id, String expression,
UIComponent parent, AjaxBehaviorListener listener) {
HtmlInputText text = new HtmlInputText();
text.setId(id);
if (!expression.isEmpty()) {
text.setValueExpression("value", createValueExpression(expression));
}
AjaxBehavior ajax = (AjaxBehavior) FacesContext.getCurrentInstance()
.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
ajax.setExecute(Arrays.asList(new String[] { "#form" }));
ajax.setRender(Arrays.asList(new String[] { "#all" }));
ajax.addAjaxBehaviorListener(listener);
text.addClientBehavior("valueChange", ajax);
add(text, parent);
return text;
}
The function for creating the fields depending on a list with the desired field informations and the listener:
public void createSearchFields(UIComponent parent) {
String beanname = Utilities.lookupManagedBeanName(this);
GUIHelper helper = GUIHelper.instance();
for (Searchfield searchfield : shown) {
helper.label(searchfield.id, searchfield.displayname, parent);
for (Field f : searchdto.getClass().getDeclaredFields()) {
GUISearchField gsf = f.getAnnotation(GUISearchField.class);
if (gsf == null)
continue;
if (gsf.id().equals(searchfield.id)) {
String expression = "#{" + beanname + ".searchdto."
+ f.getName() + "}";
helper.inputText(searchfield.id, expression, parent, this);
}
}
}
}
#Override
public void processAjaxBehavior(AjaxBehaviorEvent event)
throws AbortProcessingException {
ajax(event);
}
public abstract void ajax(AjaxBehaviorEvent event);
The xhtml part:
<h:form id="searchform" styleClass="ibm-column-form ibm-styled-form">
<h:panelGrid columns="2" binding="#{systemsearchable.searchfields}">
</h:panelGrid>
<h:commandButton value="Search" action="#{systemsearchable.search}">
<f:ajax execute="#form" render="results"></f:ajax>
</h:commandButton>
</h:form>
If you need more info please let me know :)

Ajax Call get null value in backing bean in jsf

I have two SelectoneMenu and one inputText. within inputText I called one Ajax event(blur). But this ajax method does not get selected value from SelectoneMenu. But I called the same method using CommandButton it will get selected values and worked fine.
Here is My Code:
<h:form id=HarvestRateForm>
<table width="670px;">
<tr>
<td width="100px;"><p:outputLabel value="Crushing Season" for="crushingSeason"/></td>
<td width="80px;">
<p:selectOneMenu id="crushingSeason" style="width: 110px;" value="#{harvestRateBean.selectedSeason}">
<f:selectItem itemValue="#{null}" itemLabel="Select"/>
<f:selectItems value="#{harvestRateBean.seasons}"/>
</p:selectOneMenu><p:growl for="crushingSeason"/>
</td>
<td width="60px;" align="right"><p:outputLabel value="Plant" for="plant"/></td>
<td width="80px;"><p:selectOneMenu id="plant" style="width: 85px;" value="#{harvestRateBean.selectedPlant}">
<f:selectItem itemValue="#{null}" itemLabel="Select"/>
<f:selectItems value="#{harvestRateBean.plants}"/>
</p:selectOneMenu><p:growl for="plant"/></td>
<td width="60px;" align="right"><p:outputLabel value="Plot No" for="plotNo"/></td>
<td><p:inputText id="plotNo" value="#{harvestRateBean.sapPlotNo}" size="16">
<p:ajax event="blur" listener="#{harvestRateBean.loadPlotDetails}"
update="HarvestRateForm:plotNo HarvestRateForm:ryotCode"/>
</p:inputText>
<p:growl for="plotNo"/>
</td>
</tr>
<tr>
<td><p:outputLabel value="Ryot No" for="ryotCode"/></td>
<td><p:inputText value="#{harvestRateBean.ryotNo}" size="15" id="ryotCode" readonly="true" style="background: transparent;background-color: #cccccc"/></td>
My Bean Class:
public class HarvestRateBean implements Serializable {
private Map<String, String> seasons;
private Map<String, String> plants;
private String selectedPlant;
private String selectedSeason;
private String sapPlotNo;
private String ryotNo;
public HarvestRateBean() {
seasons = new HashMap<String, String>();
plants = new HashMap<String, String>();
}
public Map<String, String> getSeasons() {
List<Season> season_list = loadSeason();
for (Iterator<Season> it = season_list.iterator(); it.hasNext();) {
Season season1 = it.next();
seasons.put(season1.getSeason(), season1.getSeason());
}
return seasons;
}
public void setSeasons(Map<String, String> seasons) {
this.seasons = seasons;
}
public List<Season> loadSeason() {
Session session = HibernateUtil.getSessionFactory().openSession();
List<Season> seasonlist = null;
try {
seasonlist = session.createCriteria(Season.class).list();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
session.close();
HibernateUtil.getSessionFactory().close();
}
return seasonlist;
}
public Map<String, String> getPlants() {
List<Plant> plant_list = loadPlants();
for (Iterator<Plant> it = plant_list.iterator(); it.hasNext();) {
Plant plant = it.next();
plants.put(plant.getId().getPlant(), plant.getId().getPlant());
}
return plants;
}
public void setPlants(Map<String, String> plants) {
this.plants = plants;
}
public List<Plant> loadPlants() {
Session session = HibernateUtil.getSessionFactory().openSession();
List<Plant> plantlist = null;
try {
plantlist = session.createCriteria(Plant.class).list();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
session.close();
}
return plantlist;
}
public String getSelectedPlant() {
return selectedPlant;
}
public void setSelectedPlant(String selectedPlant) {
this.selectedPlant = selectedPlant;
}
public String getSelectedSeason() {
return selectedSeason;
}
public void setSelectedSeason(String selectedSeason) {
this.selectedSeason = selectedSeason;
}
public String getSapPlotNo() {
return sapPlotNo;
}
public void setSapPlotNo(String sapPlotNo) {
this.sapPlotNo = sapPlotNo;
}
public String getRyotNo() {
return ryotNo;
}
public void setRyotNo(String ryotNo) {
this.ryotNo = ryotNo;
}
public void loadPlotDetails {
Session session = HibernateUtil.getSessionFactory().openSession();
List<HarvesterRate> rateList = null;
FacesContext context = FacesContext.getCurrentInstance();
try {
if (getSelectedSeason() == null || getSelectedSeason().isEmpty()) {
context.addMessage(null, new FacesMessage("Season is required", ""));
} else if (getSelectedPlant() == null || getSelectedPlant().isEmpty()) {
context.addMessage(null, new FacesMessage("Plant is required", ""));
} else if (getSapPlotNo() == null || getSapPlotNo().isEmpty()) {
context.addMessage(null, new FacesMessage("Plot No is required", ""));
} else {
rateList = session.createCriteria(HarvesterRate.class).add(Restrictions.eq("id.season", getSelectedSeason())).add(Restrictions.eq("id.plant", getSelectedPlant())).add(Restrictions.eq("id.plotNo", getSapPlotNo())).list();
if (rateList.size() > 0) {
for (Iterator<HarvesterRate> it = rateList.iterator(); it.hasNext();) {
HarvesterRate harvesterRate = it.next();
setSapPlotNo(harvestRate.getPlotNo());
setRyotNo(harvestRate.getVendorCode());
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
getSelectedSeason() and getSelectedPlant() always return null in ajax Call but I Called same method using CommandButton it return Selected value and everything works fine.
The <p:ajax> will by default process only the parent ClientBehavior component, which is in your particular case the <p:inputText>. In other words, the actual value of <p:ajax process> is #this. If you actually want to process the entire form, then you should be using #form as in
<p:inputText ...>
<p:ajax process="#form" ... />
</p:inputText>
The process attribute of <p:commandButton> defaults to #form, that's why it works therewith.
Or, if you have more input components in the form and intend to process only the input and those two dropdowns, then you can specify the (relative) client IDs space separated:
<p:inputText ...>
<p:ajax process="crushingSeason plant #this" ... />
</p:inputText>
Implement ajaxEvent in bean class
Ajax event is not like normal method rather than it invokes the listeners as input, you can configure the Blur action on a text field as following
In JSF page
<p:inputText id="name" value="#{loginBean.name}">
<f:ajax event="blur" listener="#{loginBean.ajaxEvent}" />
</p:inputText>
Ensure that the above must be inside in <h:form>
In ManagedBean class
public void ajaxEvent(AjaxBehaviorEvent e)
{
//Do your stuffs
}
Know more about JSF start from here

JSF 2 -- Save All Valid Component Values

I have a requirement to create a javascript function that when invoked will save all of the valid components on a JSF 2.0 form. Since the complete form will never be valid as a whole I need to figure out a way to run the lifecycle per component so that if the validation phase is successful the model will be updated and eventually saved.
Ideally, this needs to be a single ajax request as iterating over each component with a separate ajax request would be painfully inefficient.
Has anyone solved the problem before? If not could you give me some pointers on possible implementations?
Edit:
Here's what I have that seems to be working well so far:
#ManagedBean(name = "partialAppSaveBean")
#RequestScoped
public class PartialAppSaveBean implements Serializable {
protected static final Logger LOGGER = LoggerFactory.getLogger(PartialAppSaveBean.class);
private static final long serialVersionUID = 1L;
/**
* Save any valid Application values
*
* #param event
*/
public void saveData(AjaxBehaviorEvent event) {
final FacesContext context = FacesContext.getCurrentInstance();
UIForm form = getParentForm(event.getComponent());
Set<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
form.visitTree(VisitContext.createVisitContext(context, null, hints), new VisitCallback() {
#Override
public VisitResult visit(VisitContext context, UIComponent component) {
if (component instanceof UIInput) {
UIInput input = (UIInput) component;
input.validate(context.getFacesContext());
if (input.isValid() && input.getValue() != null) {
ValueExpression valueExpression = input.getValueExpression("value");
if (valueExpression != null
&& valueExpression.getExpressionString() != null) {
try {
valueExpression.setValue(context.getFacesContext().getELContext(), input.getValue());
} catch (Exception ex) {
LOGGER.error("Expression [ " + valueExpression.getExpressionString() +
"] value could not be set with value [" + input.getValue() + "]", ex);
}
}
}
}
return VisitResult.ACCEPT;
}
});
//Save data here
}
/**
* Returns the parent form for this UIComponent
*
* #param component
* #return form
*/
private static UIForm getParentForm(UIComponent component) {
while (component.getParent() != null) {
if (component.getParent() instanceof UIForm) {
return (UIForm) component.getParent();
} else {
return getParentForm(component.getParent());
}
}
return null;
}
}
Invoked with something like:
<h:commandButton
id="saveData">
<f:ajax listener="#{partialAppSaveBean.saveData}" execute="#form" immediate="true" onevent="onPartialSave" />
</h:commandButton>
You could use UIComponent#visitTree() on the UIForm.
FacesContext context = FacesContext.getCurrentInstance();
UIForm form = getFormSomehow();
Map<String, Object> validValues = new HashMap<String, Object>();
Set<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
form.visitTree(VisitContext.createVisitContext(context, null, hints), new VisitCallback() {
#Override
public VisitResult visit(VisitContext context, UIComponent component) {
if (component instanceof UIInput) {
UIInput input = (UIInput) component;
if (input.isValid()) {
validValues.put(input.getClientId(context.getFacesContext()), input.getValue());
}
}
return VisitResult.ACCEPT;
}
});

Custom View Scope with SetPropertyActionListener

I'm using Spring with a custom view scope to create view scope beans. This works fine until I tried to inject a property using setPropertyActionListener. This works fine if I change the bean to request scope.
This is my view scope impl:
public class ViewScope implements Scope {
public Object get(String name, ObjectFactory<?> objectFactory) {
if (FacesContext.getCurrentInstance().getViewRoot() != null) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
} else {
return null;
}
}
public Object remove(String name) {
if (FacesContext.getCurrentInstance().getViewRoot() != null) {
return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
} else {
return null;
}
}
public void registerDestructionCallback(String name, Runnable callback) {
// Do nothing
}
public Object resolveContextualObject(String key) {
return null;
}
public String getConversationId() {
return null;
}
}
and my JSF:
<h:commandLink action="confirm.xhtml">
<f:setPropertyActionListener target="#{quoteHolder.item}" value="#{quote}"/>
</h:commandLink>

Resources