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.
Related
I'm working on icefaces upgrade from 1.8 to 3.3 as well as jsf from 1.2 to 2.0.
I have used this link as reference for icefaces upgrade
I'm using ice:datatable in which I have column of checkbox which is grouped for single worker.Check picture which is of before upgrade.
ISSUE 1:
Now Problem faced after migration is that the valuechangelistener of ice:selectbooleancheckbox works fine when I check then uncheck the checkbox of a single worker. But when I do following steps:
Check first worker (This updates the Assigned door column ).
Then check other worker . This unchecks the previous checked worker and also unchecks currently checked worker.
To analyse if there is any issue in phase I used balus C blog to check phase of icefaces when it hits valuechangelistner . Then I found on my second check 2 or more valuechangelistner are called one for previous worker other for current worker(Sometimes twice) this all happens in same invoke application phase.
ISSUE 2:
ValueChangeListener gets called even after Clicking "OK" button or "CANCEL".
Fixed it by adding f:param in ice:commandButton and checking for the param in valuechangelistener method.
Tried:
To change all ice tags in the page to ace tags(Related to datatable i.e datable ,row and column).
Result : Same issue with ace valuechangelistener as well as distorted style. Maybe because I could not find ice:rowHeader equivalent in ace tags and also much more.
Changed only checkbox column to ace:column. Valuechangelistener worked fine but issue with "groupOn" attribute so changed it to "groupBy" and condition="group" still may be it did not work because I used ice:datatable which doesn't support it.
Then I tried to implement groupOn functionality manually. Using rowspan and rendering single checkbox for single worker . But rowspan didn't work. Also when I tried to render checkbox, its style is not exactly same as I need. Check this hattp://postimg.org/image/ih2mgoh7d/ remove 'a' from 'hattp'.
<ace:column groupBy ="#{item.workerName} + #{item.workerId}" rowspan="2"
styleClass= "alignSBChbx" >
<ice:setEventPhase events="ValueChangeEvent"
phase="INVOKE_APPLICATION">
<ice:selectBooleanCheckbox id="dwaCheckbox" value="#{item.select}"
style=" width:'#{appViewSettings.checkboxSize}';
height:'#{appViewSettings.checkboxSize}';"
valueChangeListener="#{dockWorkerAssignmentBean.doorAssignmentChange}"
partialSubmit="true" immediate="true"
disabled="#{!empty dockWorkerAssignmentBean.errorMap['dockWorkersAssignmentPopup:assignmentErrorField']}"
rendered="#{item.visible}">
<f:attribute name="workerIdSelected" value="#{item.workerId}" />
<f:attribute name="assignmentIdSelected" value="#{item.assignmentId}" />
</ice:selectBooleanCheckbox>
</ice:setEventPhase>
</ace:column>
backend
public final void doorAssignmentChange(final ValueChangeEvent event) {
System.out.println("inside door Assignment...");
final String workerIdSelected = (String) event.getComponent().getAttributes().get(
"workerIdSelected");
// unrelevant code
}
}
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}')/>
I need your help..., please...
I'm in the middle of a migration process from JSF 1.2 to JSF 2.1.
The Implementation I use is Sun's Mojarra implementation with facelets, which in JSF 1.2 were not part of the standard but, since JSF 2.0 they become.
Right now I am using javax.faces.PARTIAL_STATE_SAVING as true. (Tried with false, but none of my custom components worked.)
We have some custom JSF components, and in most cases they are working fine. However, the following example is not working correctly:
<ui:repeat value="#{myBean.list}" var="item">
<tr style="cursor:pointer;">
<td class="texttable col_med col15Personal">
<bf:TextBox
compId="aliasName"
value="#{item.aliasName}"
compStyle="font-size:1em;"
maxLength="15" showAutoLabel="false"/>
</td>
</tr>
</ui:repeat>
bf:TextBox is a custom text box which extends HtmlPanelGroup and has 2 custom children components:
A custom label (extending HtmlOutputlabel) and aa custom input(extending HtmlInputText)
When this component is used without ui:repeat, everything works fine. However when inside it, problems occur.
In the first renderreponse phase, everything is fine. But when you do a post, in the restoreview phase, the children of the custom HtmlPanelGroup (label and inputText) are not present in the viewRoot, so the values submitted are not present.
The same code snipped was working in the JSF 1.2 correctly.
I know that there are alternatives to ui:repeat (example c:forEach), but since I'm working on a migration process it's really complex to change all code involving this type mentioned.
Thank you all in advance,
I have found a workaround for my issue. As the main goal was to make minimum changes into application... I avoided changing the all pages that were using ui:repeat. Instead, I have changed my custom component to save the children into State Holder (saveState method) and then I restore the children if the component has a ui:repeat as parent.
if (getInsideUIRepeat() != null && getInsideUIRepeat().booleanValue()) {
values[42] = this.getChildren();
}
this is extracted from saveState method.
if (getInsideUIRepeat() != null && getInsideUIRepeat().booleanValue()) {
List<UIComponent> children = (List<UIComponent>) values[42];
if (children != null) {
this.getChildren().clear();
this.getChildren().addAll(children);
}
}
this is extracted from restoreState method.
private boolean hasUIRepeatAsParent() {
UIComponent parent = this.getParent();
while (parent != null) {
if (parent instanceof UIRepeat) {
return true;
}
parent = parent.getParent();
}
return false;
}
this is the method that checks if component has UIRepeat as parent
Thank you all again...
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.
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}" ...>