I'm creating a page to build forms and I'm using PrimeFaces component's dashboard to store and order the fields of the form. The problem is: When I try to add a new form field, by sending two input values to the Bean, the get method of dashboard is called before the set method os inputs, so I can't add the input values to dashboard.
Form.xhtml:
<h:form id="dashboardForm">
<h:panelGrid columns="4" cellpadding="5">
<p:outputLabel for="formName" value="Form Name"></p:outputLabel>
<p:inputText id="formName" placeholder="Exemple Form"></p:inputText>
</h:panelGrid>
<hr></hr>
<p:layout>
<p:layoutUnit position="west" minSize="150">
<p:panel header="Add Field">
<h:panelGrid columns="2" cellpadding="5" id="newField">
<p:outputLabel for="newFieldName" value="Question"></p:outputLabel>
<p:inputTextarea id="newFieldName" value="#{monitoringFormDashboard.newFieldName}"></p:inputTextarea>
<p:outputLabel for="newFieldType" value="Type"></p:outputLabel>
<p:selectOneMenu immediate="true" id="newFieldType" value="#{monitoringFormDashboard.newFieldType}">
<f:selectItem itemLabel="Text" itemValue="0"></f:selectItem>
<f:selectItem itemLabel="Dropdown" itemValue="1"></f:selectItem>
<f:selectItem itemLabel="Boolean" itemValue="2"></f:selectItem>
</p:selectOneMenu>
</h:panelGrid>
<p:commandButton id="addNewField" value="Add" actionListener="#{monitoringFormDashboard.addField}" update="dashboard" image="ui-icon ui-icon-carat-1-e" />
</p:panel>
</p:layoutUnit>
<p:layoutUnit position="center">
<p:dashboard id="dashboard" binding="#{monitoringFormDashboard.dashboard}">
</p:dashboard>
</p:layoutUnit>
</p:layout>
</h:form>
When I press the Add commandButton, the method execution order on bean is:
getDashboard
setDashboard
getNewFieldName
getNewFieldType
setNewFieldName
setNewFieldType
addField
So this is exactly the inverse order of what I need. I need first the newFieldName and newFieldName and later call addField and at least getDashboard...
Here is the bean class if needed: http://pastebin.com/fcCnAYNZ
What is it that I'm missing?
I've found the problem. It's related to the binding, as I read from another great #BalusC answer:
How biding attribute in jsf works
After removing binding and using another approach, it worked like a charm.
Related
I want to change my ActionListener of commandButton depending on the icon selected in advance:
<p:dialog id="dialog" header="Add Memo" widgetVar="dialogMemo" resizable="false" >
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="commentInput" value="Comment:" />
<p:inputTextarea id="commentInput" value="#{dashboardBean.getCurrentComment()}" rows="6" cols="25" label="commentInput"/>
<p:watermark for="commentInput" value="Enter your memo..."/>
<h:outputLabel for="selectShare" value="Share Memo: " />
<p:selectBooleanCheckbox id="selectShare" />
<h:outputLabel for="choosePriority" value="Priority:" />
<p:selectOneMenu id="choosePriority" value="#{dashboardBean.currentPriority}" label="choosePriority">
<f:selectItem itemLabel="Low Priority" itemValue="1" />
<f:selectItem itemLabel="Medium Priority" itemValue="2" />
<f:selectItem itemLabel="High Priority" itemValue="3" />
</p:selectOneMenu>
<p:commandButton id="submitDialog" icon="ui-icon-check" value="Confirm" ajax='false' type="submit" action="#{dashboardBean.getLastMemo()}"/>
<p:commandButton icon="ui-icon-close" onclick="dialogMemo.hide();" value="Cancel"/>
</h:panelGrid>
</h:form>
</p:dialog>
<p:layout fullPage="true">
<p:layoutUnit id="leftPanel" position="west" size="250" header="My Memos" resizable="false" closable="false" collapsible="false">
<h:form id="form">
<p:commandButton id="addMemo" icon="ui-icon-plus" onclick="dialogMemo.show();" type="submit" action="#{dashboardBean.getEditControl}"/>
<p:dashboard id="dashboardId" model="#{dashboardBean.model}" binding="#{dashboardBean.dashboard}">
</p:dashboard>
</h:form>
</p:layoutUnit>
</h:body>
When i click to command button (id="addMemo"), i want to change actionListener to commandButton(id="submitDialog").
I try that with:
public void getEditControl()
{
UIViewRoot view = _context.getViewRoot();
CommandButton button = (CommandButton) view.findComponent("submitDialog");
System.out.println("I am ID ==== [ " + button.getId() +" ]");
}
But 'button.getId()' does't work.
But 'button.getId()' does't work.
I gather that this is because the button is actually null and therefore the attempt to invoke the getId() method threw a NullPointerException? It's surprising that you stated the problem like that, "button.getId() doesn't work" instead of like "view.findComponent() returned null" (which has in turn the pretty obvious consequence that any attempt to access it would throw NullPointerException). If you had indeed no clue why it threw NullPointerException, then I strongly recommend to take a JSF pause and learn basic Java first.
Coming back to the concrete problem, the findComponent will return null when the client ID submitDialog doesn't exist in the component tree. Indeed, you have it inside a <h:form> which is a NamingContainer component. The button's client ID is more likely formId:submitDialog where formId is the ID of the button's parent form which you have to assign yet. An easy way to find out it is checking the ID of the generated HTML representation of the button.
See also this related question: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar" Just substitute "ajax" in the answer with findComponent.
I am not sure that the way you do this is the right way.
If you want to get component instance better way to do this will be not get it by id but add
<p:commandButton id="submitDialog" icon="ui-icon-check"
value="Confirm" ajax='false' type="submit"
action="#{dashboardBean.getLastMemo()}" binding="#{dashboardBean.component}" />
and that way the property in the bean will always have the component instance that you need.
Note that the scope of bean where you put component binding should be view to avoid side affects.
Let's say as for an example, I have some input fields like,
<p:panel id="panel" closable="false" toggleOrientation="horizontal" toggleable="true" header="New">
<p:focus context="panel"/>
<p:watermark for="txtCountryName" value="Enter a valid country name."/>
<p:watermark for="txtCountryCode" value="Enter a valid country code."/>
<p:messages id="systemMessages" globalOnly="true" redisplay="false" showDetail="true" showSummary="true" autoUpdate="false" closable="true"/>
<p:messages id="specificSystemMessages" for="paramId" globalOnly="false" redisplay="false" showDetail="true" showSummary="false" autoUpdate="false" closable="true"/>
<h:panelGrid id="panelGrid" columns="3" cellpadding="5">
<p:outputLabel for="txtCountryName" value="Country"/>
<p:inputText id="txtCountryName" value="#{countryManagedBean.txtCountryName}" label="Country name" required="true" maxlength="45">
<f:validateLength minimum="2" maximum="45"/>
</p:inputText>
<p:message for="txtCountryName" showSummary="false"/>
<p:outputLabel for="txtCountryCode" value="Country Code"/>
<p:inputText id="txtCountryCode" value="#{countryManagedBean.txtCountryCode}" required="true" maxlength="45" label="Country code">
<f:validateLength minimum="2" maximum="45"/>
</p:inputText>
<p:message for="txtCountryCode" showSummary="false"/>
<p:commandButton id="btnSubmit" update="dataTable panel messages" actionListener="#{countryManagedBean.insert}" icon="ui-icon-check" value="Save"/>
</h:panelGrid>
</p:panel>
And a DataTable as follows.
<p:panel id="dataTablePanel" toggleable="true" toggleOrientation="horizontal" closable="false" header="Data">
<p:dataTable id="dataTable" var="row" value="#{countryManagedBean}"
lazy="true"
pageLinks="10"
paginator="true"
sortMode="multiple"
resizableColumns="true"
sortOrder="descending"
editable="true"
filterEvent="keyup"
selection="#{countryManagedBean.selectedValues}"
rowsPerPageTemplate="5,10,15"
rows="10"
rowKey="#{row.countryId}"
rowIndexVar="rowIndex"
rowStyleClass="#{row.countryId eq countryManagedBean.id? 'selected-data-row' : null}"
editMode="row">
...
...
...
</p:dataTable>
</p:panel>
When this command button,
<p:commandButton id="btnSubmit" update="dataTable panel messages" actionListener="#{countryManagedBean.insert}" icon="ui-icon-check" value="Save"/>
is clicked, a row is added to the underlying database, if it satisfies all of the validation rules and the DataTable is updated using the update="dataTable panel messages" attribute.
I would like updating this DataTable if and only if all the validation criteria as specified on these input fields are satisfied and the row is actually created.
If anyone of these validation rules fails, then this DataTable should not be updated anymore which is quite unnecessary and causes some costly JPA criteria and/or JPQL queries to be executed. Is this possible, how?
It is Primefaces 3.5.
Try using remotecommand in that case.
Change your submit button as shown below.
<p:commandButton id="btnSubmit" action="#{countryManagedBean.insert}" icon="ui-icon-check" value="Save" oncomplete="handleRequest(xhr, status, args)"/>
Add p:remoteCommand as shown below.
<p:remoteCommand name="updateTable" update="dataTable">
This remote command will be used for updating your table.
And yes, add below js.
<script type="text/javascript">
function handleRequest(xhr, status, args) {
if(!args.validationFailed) {
updateTable();
}
}
</script>
HTH
try to add this code to your bakedbean countryManagedBean at the end of the insert function or whereever you check the validation.
RequestContext context = RequestContext.getCurrentInstance();
context.addCallbackParam("validationFailed", "true");
This creates The callback param that you check with the javascript.
I would like to submit value form jsf page to bean from overlayPanel with checkbox like this:
To show overlay panel and ajax submission I use this code, and see it's OK in debugger:
<p:commandButton id="joinBtn" value="Basic" type="button" disabled="#{dataPropertyCurrent.notJoinable}"/>
<p:overlayPanel id="joinPanel" for="joinBtn" appendToBody="true" dynamic="false">
<f:facet name="header">Details</f:facet>
<p:dataList value="#{treeBean.getDataPropsCouldBeJoinedWith(dataPropertyCurrent)}" type="definition" var="dataJoinVal">
<h:panelGrid columns="2" cellpadding="10">
<h:column>
<p:selectBooleanCheckbox value="#{dataJoinVal.checked}" id="cbID">
<p:ajax event="change" update="cbID" partialSubmit="true"/>
</p:selectBooleanCheckbox>
</h:column>
<h:column>
<h:outputText value="#{dataJoinVal.caption}" />
</h:column>
</h:panelGrid>
</p:dataList>
<!--<p:commandButton value="Apply" id="btnApplyJoin" type="button" process="#parent" />-->
<h:outputLabel value="ID: #{dataPropertyCurrent.joinDataPropertyId}" />
</p:overlayPanel>
But after it when the overlayPanel is hidden and form submit button being pressed with this code:
<p:commandButton value="Apply join" update="joinAccordionPanel,dsAccordionPanelMain" actionListener="#{treeBean.applyJoinOptions}" />
it sets "false" to bean boolean value again.
So how to submit overlayPanel value to bean properly?
PrimeFaces version: 3.5
I've found explanation here: http://forum.primefaces.org/viewtopic.php?f=3&t=30550#p97737:
"If you are using appendToBody, it's strongly recommended to have a form inside the overlayPanel component that wraps all of the input fields and buttons. This is what you have done in your last solution. However, this means that you cannot place the overlayPanel inside another form in the xhtml page because of the limitation on nesting forms. The best solution is typically to avoid appendToBody wherever it's not absolutely necessary."
Edit
I've added <h:form> inside overlayPanel, and now it works fine:
<p:overlayPanel id="joinPanel" for="joinBtn" appendToBody="true" dynamic="true" >
<h:form id="formTmp">
<f:facet name="header">Details</f:facet>
<p:dataList value="#{treeBean.getDataPropsCouldBeJoinedWith(dataPropertyCurrent)}" type="definition" var="dataJoinVal">
<h:panelGrid columns="2" cellpadding="10">
<h:column>
<p:selectBooleanCheckbox value="#{dataJoinVal.checked}" id="cbID">
<p:ajax event="change" update="cbID" partialSubmit="true"/>
</p:selectBooleanCheckbox>
</h:column>
<h:column>
<h:outputText value="#{dataJoinVal.caption}" />
</h:column>
</h:panelGrid>
</p:dataList>
</h:form>
</p:overlayPanel>
I a have a JSF page with PrimeFaces with some input fields. Before a submit is done, I would like to use the value of a field as input for a method which does some calculations and updates another field with the result but without submitting the form.
This is the field that will be used as input for my method:
<h:outputLabel for="hiredate" value="#{msgs['addUser.hireDate']}" />
<p:calendar id="hiredate" value="#{userWizardMB.user.hireDate}" required="true" immediate="true"/>
<p:message for="hiredate" />
The calculation is done by clicking a <p:commandButton>:
<p:commandButton value="Calculate days" icon="ui-icon-circle-check" action="#{userWizardMB.calculateVacationDays}" update="vacationDays" process="#this" immediate="true"/>
And this is the method called:
public void calculateVacationDays() {
user.setVacationDays((int) vacationDaysCalculator
.calculateWithHireDate(user.getHireDate()));
}
When debugging, though, I see that this field is NULL even if I set value in the form.
How can I force the setting of this field - user.hireDate because I really need this value for my calculation?
Thank you
Edit: I removed all of the other fields in the form and the immediate attribute:
<h:form id="addUserForm">
<p:wizard widgetVar="wizard" flowListener="#{userWizardMB.onFlowProcess}">
<!-- TAB FOR PERSONAL DATA -->
<p:tab id="personal" title="#{msgs['addUser.personalTab']}">
<p:panel header="#{msgs['addUser.personalInformation']}">
<p:message for="vacationDays" showDetail="true" autoUpdate="true" closable="true"/>
<h:panelGrid columns="3" columnClasses="label, value" styleClass="grid">
<h:outputLabel for="hiredate" value="#{msgs['addUser.hireDate']}" />
<p:calendar id="hiredate" value="#{userWizardMB.user.hireDate}" required="true" />
<p:message for="hiredate" />
<h:outputLabel for="vacationDays" value="#{msgs['addUser.vacationDays']}"/>
<p:inputText id="vacationDays" value="#{userWizardMB.user.vacationDays}"/>
<p:commandButton value="Calculate days" icon="ui-icon-circle-check" action="#{userWizardMB.calculateVacationDays}" process="#this hiredate" update="vacationDays"/>
</h:panelGrid>
</p:panel>
</p:tab>
</p:wizard>
</h:form>
And the backing bean method is still not called.
Remove immediate="true" from the input and the command component. Do not use immediate unless you really understand what it should be used for. Further you also need to include the input component which you'd like to process in the update attribute of the command component. Note that this should represent the client ID, not the property name as mentioned in one of your comments.
<p:calendar id="hiredate" value="#{userWizardMB.user.hireDate}" required="true" />
...
<p:commandButton value="Calculate days" icon="ui-icon-circle-check"
action="#{userWizardMB.calculateVacationDays}"
process="#this hiredate" update="vacationDays" />
See also:
Why was "immediate" attribute added to the EditableValueHolders?
Use process="#form" (or process="[the id of the calendar component]" in the commandButton
process="#this" means that only the part of the model related to the commandButton (usually none) gets updated.
Old question, but did you add partialSubmit="true" in the commandButton tag? At least in PrimeFaces 3.5, false is the default value of this attribute (see the PrimeFaces PDF documentation).
I would like to give the content of an inputText as a parameter to a function in a backing bean, I know that I could send the content in the backing bean, but it doesn't make much sense in my object model. I know that in the datatable, you can provide a function with the name of the "var", I thought I could use the same mechanism by passing the ID of the inputText, but it always sends null. Is there a way to do it ?
<p:dialog id="dialog" header="Reason for obsolescence" modal="true" widgetVar="dlg">
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="reason" value="Reason for obsolescence :" />
<p:inputText value="default" id="reason" required="true" label="reason" />
<p:commandButton id="provideReason" value="Ok" update=":form:tabView:table-metadata"
action="#{tableMetadataController.setSelectedObsolete(reason)}"
oncomplete="dlg.hide()"/>
</h:panelGrid>
</h:form>
</p:dialog>
Thanks