Hiding JSF elements with Java - java

The java code returns a column from a SQL query and if the item isn't null, sets the title to "Available".
String sppAcronym = results.getString("ACRONYM");
if (sppAcronym != null) {
sp.setFireStudyTitle("Available");
}
The JSF code makes a button labeled "Available" for all of the non-null items.
<h:column headerClass="columnHeader" footerClass="columnFooter" itemValue="0">
<f:facet name="header">Link to FEIS Fire Studies</f:facet>
<h:commandButton id="btnSearch" value="#{SPP.fireStudyTitle}"
action="#{searchBean.doMagic(SPP.acronym)}"
immediate="true" onchange="submit();"
style="font-weight:bold; font-size:small;"
onclick="javascript:cursor_wait()" class="buttonsFEIS"/>  
</h:column>
My problem is that JSF makes small, empty commandButtons even for the null items.
How can I make it so I can hide those empty commandButtons and display only the non-null items?

Use rendered attribute of the <h:commandButton> to control if the component must display or not in the generated HTML:
<h:commandButton id="btnSearch" value="#{SPP.fireStudyTitle}"
action="#{searchBean.doMagic(SPP.acronym)}"
immediate="true" onchange="submit();"
style="font-weight:bold; font-size:small;"
onclick="javascript:cursor_wait()" class="buttonsFEIS"
rendered="#{not empty SPP.acronym}" />

Related

Primefaces datatable cell editing doesn't update

I have a primefaces datatable with cell editing which is toggled on a boolean variable in the view.
I have three issues:
In edit mode, I change a value and I click the save button on the page it doesn't keep the new value, If I click anywhere else first on the page then click save it will keep the value. I need it to keep the value if you click save first.
If I edit a cell which is an input text and I click out the field now is a output text until I click in there again. I want the field to look like a input text while in edit mode.
When the save button is clicked the backing method sets the editable boolean to false, and the rest of the page obeys, and the dataTable looks like it obeyed but if you click a cell it will let you edit it.
Here is the code:
<p:dataTable value="#{view.LineItems}" var="lineItem" rowKey="#{lineItem.lineItemId}"
resizableColumns="false" editable="#{view.editable}" editMode="cell"
editingRow="#{view.editable}" id="requestLineItemsTable">
<p:ajax event="cellEdit" listener="#{view.cellEdited}" immediate="true" update="#this" />
<p:column styleClass="centerColumnData" headerText="Item Name" style="width: 140px;">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{lineItem.title}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{lineItem.title}"/>
</f:facet>
</p:cellEditor>
</p:column> ...
and this is the back end (not doing anything with this yet)
public void cellEdited(CellEditEvent event)
{
Object oldValue = event.getOldValue();
}
and here is the save and edit buttons on the same .xhtml page as datatable
<p:commandLink process="#this"
action="#{view.changeModeToEdit}"
update="#form"
rendered="#{!view.editMode">
<h:graphicImage library="images" name="edit20.png" title="#{__Common.edit}"
style="height: 15px; width: 15px;"/>
</p:commandLink>
<components:linkWithSpinner linkStyle="margin-right: 20px;" loadingImageStyle="margin-right: 20px;"
linkStyleClass="activeButton saveButtonRequestDetails" loadingImageStyleClass="saveButtonRequestDetails"
linkText="#{__CommonButton.save}"
process="#form" update="#form"
actionMethod="#{view.updateRequest()}"/>
view.updateRequest() sets the editable to false. I am using Primefaces 4.0
So I figured out a way around these issues. I was focused on using the built in edit table , but you can just have a normal datatable and the columns can contain input text fields. Then you don't have to worry about most of the issues in my question above. If you need to switch between edit and non-edit view then I still don't know how to fully fix it except have two datatables in your file with render tags, but then you are duplicating the table one with input text fields and one with output text fields, and that is not the best way to do it.

reRender rich:tabPanel without losing data

Using JSF 1.2 and Richfaces 3.3, I have this form:
<h:form>
<rich:tabPanel switchType="client" id="tabPnl">
<rich:tab label="MAIN_TAB">
<h:outputText value="#{msg.date}"/>
<rich:calendar value="#{MyBean.date}">
<f:validator validatorId="CalendarValidator" />
</rich:calendar>
<h:message for="DataInici" errorClass="error" />
<h:outputText value="#{msg.selector}"/>
<h:selectOneMenu id="select_val" value="#{MyBean.selectedItem}">
<f:selectItem itemLabel="#{msg.select_value}" itemValue="-1" />
<f:selectItems value="#{MyBean.listOfItems}" />
<f:validator validatorId="NumSelValidator" />
<a4j:support event="onchange" reRender="tabPnl" ajaxSingle="true" />
</h:selectOneMenu>
<h:message for="select_val" errorClass="error" />
</rich:tab>
<rich:tab label="SUBTAB1" id="subtab1" rendered="#{MyBean.selectedItem == 1}">
// form components such as inputText and/or SelectOneMenu.
</rich:tab>
<rich:tab label="SUBTAB2" id="subtab2" rendered="#{MyBean.selectedItem == 2}">
// Other form components such as inputText and/or SelectOneMenu.
</rich:tab>
</rich:tabPanel>
<h:commandButton value="#{msg.insert}" action="#{MyBean.insertData}">
</h:form>
At the begining, SUBTAB1 and SUBTAB2 are not rendered as the default value for MyBean.selectedItem is -1.
Firstly, the user picks a date in the <rich:calendar> component and, after that, it selects a value in the <h:selectOneMenu>. After that, the desired behaviour (what I want to achieve) is reRender the tabPanel without losing the data already introduced. Consequently, I expect the tabs SUBTAB1 or SUBTAB2 become rendered depending on what the value chosen in the <h:selectOneMenu>.
What I get: The tabPanel is reRendered, the appropiate SUBTAB is rendered but the data introduced in the first tab is lost.
How can I render these tabs without losing the data already introduced? I've tried to reRender the specific tabs, but it dosen't make them become rendered (I suppose it only affects to their content).
Thank you in advance.
Note: All beans involved are Session scoped.
Problem is that the inputs values are not processed on server.
Remove ajaxSingle="true" from a4j:support, so the whole form is processed when selectOneMenu value changes. You can use process attribute to limit the submitted area (in case you don't want to process the whole form).
ajaxSingle
Limits JSF tree processing (decoding, conversion, validation and model
updating) only to a component that sends the request. Boolean. Default
value is "false".

Update component without specifying the absolute client id

The code fragment below represents an editor. In my application, a windows displays a group of editors in a tab panel, each tab containing a datatable with the editors as rows. When a node is selected, its text will be displayed in the organizationUnit input text. The editor shouldn't know about it's parents. Is it possible to update organizationUnit without using the absolute client id?
<p:tabView value="#{accountsBean.groups}" var="group">
<p:tab title="#{eval.getString(group.name)}">
<p:dataTable value="#{group.editors}"
var="editor">
<p:column>
<custom:include src="#{editor.component}">
<ui:param name="bean" value="#{editor.beanName}"/>
<ui:param name="mandatory" value="#{editor.mandatory}"/>
<ui:param name="name" value="#{editor.name}"/>
</custom:include>
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
<h:panelGrid id="containerEditor" columns="2">
<h:outputText value="#{name}: #{mandatory ? '*' : ''}" />
<p:tree value="#{bean.root}" var="node" selectionMode="single" selection="#
{selectedNode}">
<p:ajax event="select" listener="#{bean.onNodeSelect}"
update="update_organization_unit" immediate="true" />
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
<h:outputText />
<p:inputText id="organizationUnit" value="#{bean.selectedItemPath}"
disabled="true" />
</h:panelGrid>
The tab panel is inside a form called form with prependId="false"
When you have components inside different NamingContainers, and those are not nested**, you must use absolute client id.
In your case, if you don't use the separator character at the begining, the findComponent algorithm would search up until it finds a NamingContainer: this would be your p:tree. Then it would try to find the component inside the p:tree, since it's not there, the exception you mentioned is thrown.
On the other hand, If you do use the separator character at the begining, you must use the absolute client id.
Short answers: No. Unless you change the way your components are organized, you can't update organizationUnit without using the absolute client id.
** If NamingContainers are nested, components inside the outter NamingContainer may update ones inside an inner NamingContainer by referencing their id before the id of the actual component they want to update, for example: update="innerContainer1Id:componentId", or even update="innerContainer1Id:innerContainer2:componentId".
Algorithm is explained in the JavaDoc.
A common 'trick' I use to avoid refering to ids is to use binding.
Example:
<h:form>
<p:button binding="#{button}" ...
</h:form>
....
<p:button update=":#{button.clientId}" ...
Note: This doesn't work for some tags like h:outputText that don't generate an id.

JSF autocomplete ignoring null values

I have a problem regarding jsf autocomplete elements. I want my page to have an autocomplete element and after a user selects a value from the field, another field is automatically created. The maksimum number of autocomplete field is 3, so after the 3rd one, the 4th one is disabled:
<h:outputLabel for="fieldsOfStudy" value="#{amsg.fieldsOfStudy}"/>
<p:outputPanel id="fieldsOfStudy" autoUpdate="true" layout="block">
<ui:repeat value="#{cc.attrs.offer.fieldsOfStudy}" var="studyField" varStatus="status">
<h:panelGroup id="studyField" layout="block">
<h:outputText value="#{amsg.handleGetObject(enumHelper.toMessageKey(studyField))}"/>
<p:commandLink action="#{cc.attrs.offer.removeFieldOfStudy(status.index)}" process="#this"
update="#([id$=fieldsOfStudyAutocomplete])" styleClass="ui-icon ui-icon-close"/>
</h:panelGroup>
</ui:repeat>
</p:outputPanel>
<h:message for="fieldsOfStudy" errorClass="error"/>
<h:panelGroup id="fieldsOfStudyAutocomplete">
<p:autoComplete value="#{offerBean.selectedFieldOfStudy}" dropdown="true" required="#{empty cc.attrs.offer.fieldsOfStudy}"
completeMethod="#{offerBean.completeFieldsOfStudy}" disabled="#{cc.attrs.offer.fieldsOfStudy.size() >= 3}"
itemValue="#{p}" var="p" itemLabel="#{amsg.handleGetObject(enumHelper.toMessageKey(p))}" styleClass="xLargeInput">
<p:ajax event="itemSelect" process="#this" update="#this"/>
</p:autoComplete>
</h:panelGroup>
Everything works good like this, but the problem is that every time a user presses the Save button if the "Field of study" list has 1 selected element from the autocomplete there will be another one in the list with a null value. If there are 2 selected "field of studies" the 3rd one will be also created but ill have a null value. If there are 3 selected "fields of studies", then there wont be any 4th element in the list.
Is there any way I can set the autocomplete to ignore null fields? In other words, if a user doesnt select anything from the autocomplete, how not to pass null values to the DTO?
I found a way. When setting up the value in the bean you can easily put an if statement like this:
public void setSelectedFieldOfStudy(FieldOfStudy selectedFieldOfStudy) {
if (selectedFieldOfStudy != null) {
this.emptyOffer.getFieldsOfStudy().add(selectedFieldOfStudy);
}
}

Can't persist my input text

I have an input text area, inside a panel grid. This panel grid is only rendered when a check box is ticked. I'm using a value change listener to listen to the check box to render the text area. This rendering mechanism works, but the trouble is that I can't retrieve the value the user inputs in the text area. It always returns null. Any help appreciated.
// if box is checked, input text area is rendered
public void showURL(ValueChangeEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
boolean value = (Boolean) event.getNewValue();
setRenderURL(value);
context.renderResponse();
}
<h:panelGrid columns="2" >
<h:outputLabel value="Is position vacant?" />
<h:selectBooleanCheckbox valueChangeListener="#{formBean.showURL}"
onclick="submit()"
immediate="true" />
</h:panelGrid>
<h:panelGrid columns="2" rendered="#{formBean.renderURL}" >
<h:panelGroup>
<h:outputLabel value="Link: "/>
// trouble here: getURL always returns null
<h:inputText size="60" value="#{formBean.URL}" />
</h:panelGroup>
</h:panelGrid>
Add
<h:inputHidden value="#{formBean.renderURL}" />
to the same form so that the condition for the rendered attribute is retained during the request wherein input components are processed. JSF namely won't validate/convert/update an input component whenever the rendered attribute of it or one of it parents evaluates false.

Categories