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.
Related
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.
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}" />
I am able to set my panel's position then update it however I have trouble when getting its current position.
For example:
Currently, my panel is positioned at (50, 50).
<h:form id="testForm">
<p:panel id="pane" style="position: absolute; left:50px; top:50px;">
<p:panelGrid columns=4>
<p:outputPanel id="ASlot3" styleClass="slot"/>
<p:outputPanel id="ASlot4" styleClass="slot"/>
<p:outputPanel id="ASlot5" styleClass="slot"/>
<p:outputPanel id="ASlot6" styleClass="slot"/>
</p:panelGrid>
</p:panel>
<p:draggable id="drg" for="pane"/>
<p:commandButton id="press" action="#{sbean.press}"/>
</h:form>
I update its position via dragging the panel. After dragging it, I press a button holding this method printing the contents of "style".
//press() method
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UIComponent component = viewRoot.findComponent("testForm").findComponent("pane");
Panel p = (Panel) component;
System.out.println(p.getAttributes().get("style"));
The "style" does not update after dragging the panel and pressing the button.
So how can I get my panel's current position after dragging?
EDIT: BTW, the scope I'm using is #ViewScoped
By default the PrimeFaces commandButton component operates with Ajax functionality, meaning that for the form submit to process the component with id pane you would need to declare that in the process attribute.
<p:commandButton id="press" action="#{sbean.press}" process="#this pane"
update="#this pane" />
The other option is to simply process and update the whole form.
<p:commandButton id="press" action="#{sbean.press}" process="#form"
update="#form" />
Or you can simply set Ajax functionality to Off and it will operate like a typical form submit control.
<p:commandButton id="press" action="#{sbean.press}" ajax="false" />
EDIT: I see though that the Primefaces draggable does not update the absolute position of the component to the server's View State. This is unfortunate but it can be worked around using hiddenInputs and a Javascript.
<script type="text/javascript">
function updatePanelPosition() {
var panel = jQuery('#testForm\\:pane');
var hiddenLeftInput = jQuery('#testForm\\:hiddenLeft');
var hiddenTopInput = jQuery('#testForm\\:hiddenTop');
var left = panel.css('left');
var top = panel.css('top');
hiddenLeftInput.val(left);
hiddenTopInput.val(top);
}
</script>
<h:inputHidden id="hiddenLeft" value="#{viewScopedBean.leftProperty}" />
<h:inputHidden id="hiddenTop" value="#{viewScopedBean.topProperty}" />
<p:commandButton id="press" action="#{sbean.press}" process="#form"
update="#form" onstart="updatePanelPosition()" />
The two hidden input components will get updated with the current left and top property of pane just before the submit, and then those values will get updated to managed bean properties where you will be able to fetch the values.
I know it seems messy but in the end this is really what the managed bean is good for, acting like a view controller and containing presentation logic.
After onbluring an input text field inside my form , I'm rerendering the form with the new values.
In this case the field loses it's focus, I want the input that was after the one I blured out from to be focused. is there an after render event, or somthing that will give the option to choose the cell i want to focus on?
Thank's In Advance.
I'm not sure this would work but you can try the following:
<h:form id="myForm">
<h:inputText id="my1stInput" >
<a4j:ajax event="blur" render="myForm" oncomplete="document.getElementById('myForm:my2ndInput').focus()" />
</h:inputText>
<h:inputText id="my2ndInput" />
</h:form>
A very simple JSF applicaton:
InputText element is assigned with Validator.
f:ajax is used to render next element (phoneNumber) by using blur event.
PhoneNumber will only be displayed if inputText pass the validator and isValid boolean value is set to true
Here is the code snippet
<h:form id="invOrdersWizForm">
<h:inputText id="name" maxlength="9" styleClass="ordLabelNarrow"
validator="#{person.validatePerson}"
value="#{person.name}">
<f:ajax render="phoneLabel" event="blur"/>
</h:inputText>
<h:outputText id="phoneLabel"
rendered="#{person.isValid}"
styleClass="ordLabelWide" value="#{person.phoneNumber}" />
</h:form>
ManagedBean
public void validatePerson(FacesContext context, UIComponent toValidate, Object value) {
name = ((String) value).toUpperCase();
phoneNumber = "12345678";
isValid = true;
}
The problem is, for some reason, the phoneNumber is not rendered at all.
The only way that I can make it work is by changing f:ajax to render #form
<h:inputText id="name" maxlength="9" styleClass="ordLabelNarrow"
validator="#{person.validateSecurityCode}"
value="#{person.name}">
<f:ajax render="#form" event="blur"/>
</h:inputText>
Or remove rendered from phoneNumber
rendered="#{person.isValid}"
For some reason f:ajax with specific element Id and rendered based on managedBean Attribute cannot co-exist.
Any idea or advice guys?
NOTE: this behaviour also happen when I use listener instead of validator
The f:ajax operates at the client side. The element which is specified in render must be already present in the client side HTML DOM tree. Put it in for example a h:panelGroup instead which is always rendered to the client side.
<h:panelGroup id="phoneLabel">
<h:outputText rendered="#{person.isValid}" value="#{person.phoneNumber}" />
</h:panelGroup>