DataScroller not rendererd after binding with bean - jsf-2

My goal is to reset the first page of the datascroller after a new search.
This should be done with this statement:
getTableScroller().getUIData().setFirst(index);
My problem is, after I bind the datascroller with a bean it will not be rendered. Just after I hit the search button a seccond time it will be rendered.
Bean:
public class HistoryBean {
private HtmlDataScroller tableScroller = new HtmlDataScroller();
// ...
Facelet:
<t:dataScroller id="scroll_1"
for="data"
fastStep="10"
pageCountVar="pageCount"
pageIndexVar="pageIndex"
styleClass="scroller"
paginator="true"
paginatorMaxPages="9"
paginatorTableClass="paginator"
paginatorActiveColumnStyle="font-weight:bold;"
immediate="true"
actionListener="#{historyBean.scrollerAction}"
binding="#{historyBean.tableScroller}"
>
If I remove the binding attribute it will be rendered on initial request. What have I forgotten?

You shouldn't bind the component to a bean which is in a broader scope than the request scope.
Rather specify the first attribute just straight in the view.
<t:dataScroller first="#{historyBean.index}" ...>

Related

Primefaces commandbutton clientside variable

I'm migrating richfaces to primefaces.
<a4j:commandButton id="editStatusButtonId"
data="#{userTO.emailIdMandatoryStatus}" action="#UserAdministration.editStatusButtonAction}" oncomplete="if(data=='#{UserAdministration.configureEmailSettingStatus}')/>
I need any replace attribute for data in primefaces commandabutton.
It comes as the callback parameter in primefaces, on the RequestContext component.
I'm going to "borrow" generously from the manual.
From your backing bean:
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("mandatoryStatus", userTO.emailIdMandatoryStatus); //isValid is the parameter
In your page, likely in a js function:
var mandatoryStatus= args.mandatoryStatus;
It has almost exactly the same semantics as in RF; the values are serialized as JSON, just as in RF; the data is made available on the args object, in RF - the event.data
Putting it all together, you can have:
<p:commandButton id="editStatusButtonId" action="#{UserAdministration.editStatusButtonAction}" oncomplete="if(args.mandatoryStatus=='#{UserAdministration.configureEmailSettingStatus}')/>

How to submit a form with disabled input that got a conversion error

I have the following page/bean structure (using myfaces 2.0.11 + tomcat 6)
I have one checkbox that when checked the h:inputtext (which is connected to an Integer variable in my bean) next to him is enabled and when the checkbox is unchecked the input is disabled, and I have a submit button that submits them both (entire form)
here is the code
<h:form prependId="false">
<h:selectBooleanCheckbox id="my_len" value="#{myBean.myLenBool}">
<f:ajax render="my_len_input_wrapper"/>
</h:selectBooleanCheckbox>
<h:panelGroup id="my_len_input_wrapper">
<h:inputText value="#{myBean.myLen}" id="my_len_input"
disabled="#{not myBean.myLenBool}" required="#{myBean.myLenBool}">
<f:validateLongRange minimum="1"/>
</h:inputText>
<h:message for="my_len_input"/>
</h:panelGroup>
<h:commandButton action="#{myBean.submit}" value="submit">
<f:ajax render="#form" execute="#form"></f:ajax>
</h:commandButton>
</h:form>
Bean code
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class myBean {
Integer myLen;
boolean myLenBool;
public Integer getMyLen() {
return myLen;
}
public void setMyLen(Integer myLen) {
this.myLen = myLen;
}
public boolean isMyLenBool() {
return myLenBool;
}
public void setMyLenBool(boolean myLenBool) {
this.myLenBool = myLenBool;
}
public void submit() {
// submit
}
}
The scenario is as following
1) check the checkbox (the input will be enabled)
2) enter an invalid value (for example 0.5) , its invalid cause myLen is a Integer
3) hit submit -> a error message will be shown in h:message cause of conversion error
4) uncheck the checkbox (it will disable the inputtext)
5) hit submit <--- form is not being submitted cause of the conversion error?!?!
So the question is: how can I submit the form with disabled input that got conversion error???
The only solution I found so far is writing my own custom converter that ignores conversion if the field is disabled
#FacesConverter("APCustomConverter")
public class APCustomConverter extends IntegerConverter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (component.getAttributes().get("disabled") != null && component.getAttributes().get("disabled").equals(true)) {
return null;
}
Object retValue = super.getAsObject(context, component, value);
return retValue;
}
}
Was hoping for a better solution than mine (using CustomConverter),
A bit off/not so off topic:
This conversion error eventually had lead me to a really annoying scenario in which: when I used discard button with only render="#form" the state of the checkbox and the input went so wrong that after clicking discard -> the checkbox remained checked (although it shouldn't cause form wasn't really submitted) and the input was disabled and not readonly cause the real checkbox value was false, AND when i hit submit again the checkbox became really checked but the input got himself a null value (all this cause null pointers exception on server), so eventually I had to use <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" /> by omnifaces in the discard button.
Tested with Mojarra 2.1.26 and MyFaces 2.0.11. When unchecking the checkbox, Mojarra updates the h:inputText and leaves it blank, which is the expected behaviour because the value has never reached the model (validation error). However, MyFaces only updates it to disable mode, leaving the old input value there.
That seems like a MyFaces issue, not solved even in the latest (2.1.12-2.0.18) branch versions. In fact, if you want to skip some element's conversion/validation depending on its state, writing a custom converter/validator is the way to go, but in your case the issue is tied to MyFaces' ajax cycle, which should work as Mojarra's one does.
As a solution you have three possible choices:
Switch to Mojarra implementation if possible, that would make the issue disappear.
Write some JS code in order to reset the input value when the checkbox is unselected.
Go with your current solution, which skips element conversion at server side in case of being disabled.

Expanding behavior of Richfaces Collapsible Panel

So, I have recently started working on a JSF page using richfaces 4, in which I have a rich:collapsiblePanel. I face a problem however, I am using the collapsiblePanel within a rich:dataGrid, which renders the collapsiblePanels by iterating though a list recieved from the server. There is a link to 'sort' the collapsiblePanels according to the data in the panel header (in the backing bean of course). When any of the collapsiblePanels are expanded, and the sort link is clicked, all of them are expanded, whilst all are expanded, if one is closed, and the link clicked again, all of them close.
Things I have tried:
Changing the switchType to any other than client (i.e ajax and server)
Adding a constant boolean in the backing bean to force the expand attribute to false on reload (although it is not even affected by the backing bean at all)
Sample code of what it looks like at the moment:
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="bean.listValues" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
The link simply calls a method in the backing bean which does the sorting.
I have found a similar problem, involving a dataTable instead of a dataGrid, although no answers have been given, but only links that lead to more dead ends. This can be found at: https://community.jboss.org/message/819938
Any help would be greatly appreciated. Unfortunately I do not have alot of time to answer alot of other questions at the moment, but I will be checking back a bit later.
Thanks in advance.
You have many syntax flaws inside your code, here is how it should looks like :
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
You are probably experiencing only one collapsiblePanel in your example, this code modified and tested work properly.
Now if you want to save collapsiblePanels expanded state when refreshing your dataGrid by AJAX, you need to add some stuff.
First, you need to add one property to your objects you are iterating on, to save the state of each panels.
public class Item
{
private boolean expanded;
public void setExpanded(boolean expanded)
{
this.exanded = expanded;
}
public boolean getExpanded()
{
return this.expanded;
}
// Your other stuff
}
Second, you need to add a listener in your bean to know when user changes the state of a panel, note the attribute to get back which item is related to this panel.
#ManagedBean
#ViewScope
public class Bean
{
private List<Item> listValues;
#PostConstruct
void init()
{
listValues = //... Some initialization to your list
}
public List<Item> getListValues()
{
return this.listValues;
}
public void toggle(PanelToggleEvent event)
{
// Take the current item
Item item = (Item)event.getComponent().getAttributes().get("item");
// Save the current state in the item
item.setExpanded(event.getExpanded());
}
}
Finally, you need to change your switchType to AJAX and add the listener in your code without forgetting the attribute that need to be passed in the listener.
<h:form>
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="item"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="ajax" expanded="#{item.expanded}">
<f:attribute name="item" value="#{item}" />
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:form>

Ajax attached to Composite Component updates model but does not fire listener

I have a custom component location. I want that, when a change is done, the model is update so another component (an autocomplete) is to show only results related to the location value. Also, that component is rerendered to reset it.
I have a page with the following code (simplified):
<h:form id="ticketForm">
...
<loc:location id="locationId" <-- CUSTOM COMPONENT
hiddenFieldValue="#{ticketCtrl.ticket.location}"
visibleFieldValue="#{ticketCtrl.ticket.locationDescription}"
rendered="#{ticketCtrl.ticketModifiable}">
<f:ajax event="changeLocation" render=":ticketForm:gfhId" <-- AJAX CALL.
execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
</loc:location>
...
</h:form>
When the value in the component is changed, the model is updated and :ticketForm:gfhId is rendered as needed, but the listener(which performs additional resets) is not executed.
Attaching the ajax to a simpler control results in the listener being executed; v.g.
<h:inputText id="contactId"
value="#{ticketCtrl.ticket.contactPerson}"
disabled="#{not ticketCtrl.ticketModifiable}">
<f:ajax event="change" render=":ticketForm:gfhId"
execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
</h:inputText>
works perfectly.
I do not know if it may be related as how the changeLocation event is fired; inside my component I define it as
<composite:interface>
...
<composite:clientBehavior name="changeLocation" event="change" targets="visibleId"/>
</composite:interface>
with visibleId being a readonly text; when it is changed by javascript I fire the change event on it with JS.
function launchEvent(fieldName) {
if ("fireEvent" in fieldName) {
fieldName.fireEvent("onchange");
} else {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
fieldName.dispatchEvent(evt);
}
}
The info I find in other questions is about making ajax an inner part of the composite component, here I want ajax detached because I probably won't need it in other uses of the component.
I am using JBoss 6.1 wih Mojarra 2.1.9 and Richfaces 4.
Thanks in advance.
UPDATE:
Even after finding jarek.jpa's answer right, if someone wants to check the code it is here:
The composite component
http://pastebin.com/9wqMVfR5
The main form
http://pastebin.com/i39ys2D9
This may have to do with the "readonly" attribute set to true. Though you manage to send the change-event by hand (JS), the server-side processing of the listener may be dropped due to the readonly state. See e.g. jsf (richfaces) readonly input text validation.

Composite component re-created during RENDER_RESPONSE

I am trying to write a composite component that can set focus to the first UIINput that failed validation.
My problem is that RENDER_RESPONSE is recreating my composite component from it's xhtml, rather than simply encoding the instance that I'm updating during PROCESS_VALIDATIONS. I'm using Mojarra 2.0.4 (FCS b09)
The composite implementation is
<h:outputScript name="jfocus.js" library="js" target="head"/>
<h:panelGroup layout="span" id="jimo-FocusMgr">
<script type="text/javascript">
jimo.FocusMgr.request("#{cc.attrs.target}");
</script>
</h:panelGroup>
The following code in my listener is what sets the target attribute of the composite during After PhaseId.PROCESS_VALIDATIONS, and adds the composite's (only)child to the list of renderIds. The debug output shows that prevEntry is the value that the using page set into the component, and failedId is the clientId() of the invalid UIInput.
//set the target attribute of the composite component
Object prevEntry = mgr.getAttributes().put("target", failedId);
if(log.isDebugEnabled())
log.debug("Set mgr's target attribute='"+failedId
+"', previously='"+(prevEntry==null ? "null" : prevEntry.toString()+"'"));
PartialViewContext pvc = fc.getPartialViewContext();
Collection<String> renderids = pvc.getRenderIds();
//update target has to be an official component in the DOM, so append the child panelGroup ID
if(!renderids.contains(mgr.getClientId()))
pvc.getRenderIds().add(mgr.getClientId()+UINamingContainer.getSeparatorChar(fc)+MGR_ID);
//first invalid component wins
break;
Calling mgr.getAttributes().get("target") during Before PhaseId.RENDER_RESPONSE continues to show the failedID, but the same call during After PhaseId.RENDER_RESPONSE shows that target has reverted back to the using page's value.
Is this a bug, or am I abusing/misusing composites?
Any pointers would be appreciated
Jim
Composite abuse.
You can't programaticaly modify a cc.attrs value -- it's not retrieved using it's NamingContainer UIComponent attribute map.
Tweaked the implementation to have the cc.attr refer to a managedBean property that I use c:set to initialize in the composite xhtml, and can freely update in my listener via it's setter.

Resources