How can I get my commandButton by Id? - jsf

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.

Related

Button in dialog inside p:dialog is not calling controller method

I've got a problem as described in the title.
Small description of the problem is as following:
I have button which is used to open dialog. Then, inside that dialog, there is button which opens another dialog on top of the first one. After clicking second button I want method from controller to be called but nothing happens. Value in h:outputText is read properly, so I guess it is not a problem with connection controller->view.
I'm using:
Spring web 3.1.2.RELEASE
JSF 2.2.10
Primefaces 5.1
Code:
beans.xml
<bean id="testController" class="test.TestController" />
TestController.java
public class TestController implements Serializable
{
private static final long serialVersionUID = 7028608421091861830L;
private String test;
public TestController()
{
test = "abc";
}
public void testMethod()
{
test = "cba";
}
public String getTest()
{
return test;
}
}
test.xhtml
<h:panelGrid columns="1" cellpadding="5">
<p:commandButton value="Basic" type="button" onclick="PF('dlg1').show();" />
</h:panelGrid>
<p:dialog widgetVar="dlg1">
<h:outputText value="Resistance to PrimeFaces is futile!" />
<h:panelGrid columns="1" cellpadding="5">
<p:commandButton value="Basic" type="button" onclick="PF('dlg2').show();" />
</h:panelGrid>
<p:dialog widgetVar="dlg2">
<h:outputText value="#{testController.test}" />
<p:commandButton value="Call method" type="button" actionListener="#{testController.testMethod}" />
</p:dialog>
</p:dialog>
What I tried:
adding appendToBody="true" to each p:dialog
changing from p:commandButton to p:button
changing from actionListener to action
but nothing helps.
I would be grateful for any help or advice of what can be the reason of not calling given method.
There are 3 problems.
You're nesting <p:dialog> components. This doesn't make sense. Separate them.
A <p:dialog> must have its own <h:form>, particularly when you explicitly use appendToBody="true" or appendTo="#(body)", otherwise nothing can be submitted because JavaScript would relocate the dialog out of its position in the HTML DOM tree to the end of body, causing it to not be sitting in a form anymore.
A <p:commandButton type="button"> acts as a "click" button, not as a submit button. Remove that attribute from submit buttons.
All in all, this is how it should look like:
<h:form>
<h:panelGrid columns="1" cellpadding="5">
<p:commandButton value="Basic" type="button" onclick="PF('dlg1').show();" />
</h:panelGrid>
</h:form>
<p:dialog widgetVar="dlg1">
<h:form>
<h:outputText value="Resistance to PrimeFaces is futile!" />
<h:panelGrid columns="1" cellpadding="5">
<p:commandButton value="Basic" type="button" onclick="PF('dlg2').show();" />
</h:panelGrid>
</h:form>
</p:dialog>
<p:dialog widgetVar="dlg2">
<h:form>
<h:outputText value="#{testController.test}" />
<p:commandButton value="Call method" actionListener="#{testController.testMethod}" />
</h:form>
</p:dialog>
OK. I guess I found a way to fix this problem.
It seems that the problem was:
type="button"
I deleted it from the list of attributes of each button and now it works even without h:form. Thanks for help.

change component rendering order

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.

Primefaces Confirm Message Updated Value

I'm trying to show an updated value in confirm dialog message but I keep getting the old value as in this scenario
<h:form>
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<p:commandButton value="SUBMIT" actionListener="#{bean.submit()}">
<p:confirm header="Confirmation" message="Amount is : #{bean.object.amount} ?"/>
</p:commandButton>
<p:confirmDialog global="true">
<p:commandButton value="Yes" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
<p:commandButton value="No" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
</p:confirmDialog>
</h:panelgGroup/>
</h:form>
Bean code:
#ManagedBean(name="bean")
#ViewScoped
public class Bean implements Serializable {
private SomeClass object;
#PostConstruct
public void init(){
this.object = new SomeClass();
}
public void calculate(){
//do some colculation (not related to amount field in object)
}
public void submit(){
//submit to database
}
//getter setter
}
When I enter a value in amount, lets say 50. and update the cal component I get the updated amount in the outputtext "50". However, in the confirm button message I get amount as 0 instead 50. How can I show the updated value in the confirm message?
PS:
Primefaces-4.0
Take a look at the user guide of primefaces in the confirm dialog section, in the Non-Global mode the document mentioned:
Message facet is
useful if you need to place custom content instead of simple text.
While in the Global mode, I can't find similar sentences like that, and I've tried using the facet in Global mode and it doesn't work.So,
Do you really use this confirm dialog multiple times?
If not:
I suggest you take away the global parameter and change your code like this:
<h:form>
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<p:commandButton value="SUBMIT" actionListener="#{bean.submit()}" oncomplete="PF('confirmDlg').show()"/>
<p:confirmDialog header="Confirmation" widgetVar="confirmDlg">
<f:facet name="message">
<h:outputText value='Amount is : #{bean.object.amount} ?'/>
</f:facet>
<p:commandButton value="Yes" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
<p:commandButton value="No" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
</p:confirmDialog>
</h:panelGroup>
</h:form>
.
If so:
(You do use the confirm dialog multiple times and tired of writing several dialogs with same form but different message.)
I suggest you write a dialog on your own,and you can also change the message in the dialog from backing bean like what you did:
<h:form id="myForm">
<p:inputText value="#{bean.object.amount}"/>
<p:commandButton value="CALCULATE" update="cal" actionListener="#{bean.calculate()}"/>
<h:panelGroup id="cal">
<h:outputText value="#{bean.object.amount}"/>
<ui:param name="message" value="Amount is :#{bean.object.amount}?" />
<p:commandButton value="SUBMIT" actionListener="#{bean.setMessage(message)}" action="#{bean.submit()}" update="myForm:myDialog" oncomplete="PF('myDlg').show()"/>
</h:panelGroup>
<p:dialog id='myDialog' widgetVar="myDlg" header="Confirmation" modal="true" resizable="false">
<h:panelGrid columns="3">
<h:panelGroup styleClass="ui-icon ui-icon-alert" style="float:right"/>
<h:outputText value="#{bean.message}"/>
<h:outputText/>
<h:outputText/>
<p:commandButton value="Yes" type="button" icon="ui-icon-check" oncomplete="PF('myDlg').hide()"/>
<p:commandButton value="No" type="button" icon="ui-icon-close" onclick="PF('myDlg').hide()"/>
</h:panelGrid>
</p:dialog>
</h:form>
p:confirm does not implement state saving, thus it loses its attributes' values after the first JSF lifecycle. It also evaluates EL only once at view build time.
I posted the solution in this answer.

Validator is called but error message is not displayed

when i click on the command button. validate method is getting called but the error message is not getting displayed..
here is my code..
<h:form id="form">
<h:body>
<p:panel style="width:500px">
<h:outputLabel for="year" value="Select Year: *" style="font-weight:bold" />
<p:selectOneMenu id="year" value="#{leaveBean.year}">
<f:selectItem itemLabel="Select One" itemValue="null" />
<f:selectItems value="#{leaveBean.yearDTO}" var="currentUser" itemValue="#{currentUser.name}" itemLabel="#{currentUser.name}" />
<f:validator validatorId="LeaveCardValidator" />
</p:selectOneMenu>
</p:panel>
<p:commandButton value="Submit" action="#{leaveController.leaveCard}" update="updateList,updateDetails" id="button"/>
<h:message for="year" style="color:red"/>
You seem to expect that JSF auto-updates the <h:message> on every ajax request. This is untrue. Perhaps you're confusing with PrimeFaces <p:messages> or <p:growl> which have each an autoUpdate attribute which enables you to tell them to auto-update themselves on every ajax request.
You really need to make sure that the <h:message> is covered by the ajax update. Just give it an ID
<h:message id="yearMessage" ... />
and include it in the client ID collection of the ajax update
<p:commandButton ... update="updateList updateDetails yearMessage" />
An alternative would be to replace <h:message> by <p:messages autoUpdate="true">.
Not sure where are the updateList and updateDetails are located but in the example give above you should use update="#form" instead or in addtion like this:
update="updateList updateDetails #form"
so that the form will be rendered again...
just use one of these :
update the whole form in order to update the content of
<h:message />
<p:commandButton value="Submit" action="#{leaveController.leaveCard}" update="#form" id="button"/>
or give the <h:message /> an id and id this id to the <p:commandButton/>
<h:message id="msg" for="year" style="color:red"/>
<p:commandButton value="Submit" action="#{leaveController.leaveCard}" update="updateList,updateDetails,msg" id="button"/>

primefaces dialog with inputtext as parameter

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

Resources