how does mouse event work in primefaces? - jsf

i am developing a java web application using primefaces 4.0 and jsf 2.0.
i have a text label and it's textbox. when user is in edit mode, and want to modify the value of a particular textbox, the old value of the textbox should be displayed on the right side while the user is entering the new value in the textbox. so i add an output text which rendered false on load. i want to trigger this output text(id="test") when the user click in the textbox(id="customer_customername"). so rendered should be change to equal. anyone can tell me how to do this? in my backend i have an interface with its implementation , dao and service.
<h:panelGrid id="detail1" columns="2" styleClass="grid" columnClasses="label,value">
<h:outputText value="#{customermsgs['customer.customername.title']}:" />
<h:inputText id="customer_customername" value="# {CustomerComponent.customer.customername}" onclick="#{CustomerComponent.customername}" label="customer_customername">
<f:ajax render="detail1" />
</h:inputText>
<h:outputText id="test" value="#{CustomerComponent.customer.customername}" rendered="#{CustomerComponent.visible}"/>
</h:panelGrid>
public class CustomerComponentImpl implements CustomerComponent {
/**
* Data type variable that provides CRUD operations for Customer entities
*
*/
private boolean visible=false;
private String customername;
public String getCustomername() {
return customername;
}
public void setCustomername(String customername) {
setVisible(true);
this.customername = customername;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
//some codes goes here.
Note: i have implemented the method in my interface also.
the onclick event is not working. look like it does not trigger! anyone can help?

This,
<h:inputText ... onclick="#{CustomerComponent.customername}">
does very definitely not what you thought it does. In its current form, when filled, it would only cause a JavaScript error because the #{CustomerComponent.customername} does very likely not return a piece of (syntactically valid!) JavaScript code which should be executed on click. Instead, it's more likely to return a string representing the customer name. When printed this into JavaScript context, it would only be interpreted as an undefined JavaScript variable.
As to your concrete functional requirement, the <f:ajax> listens inside input components by default only on change event. You can change this to click by setting the event attribute accordingly. All in all, this should do as you intented:
<h:inputText id="customer_customername" value="#{CustomerComponent.customer.customername}" label="customer_customername">
<f:ajax event="click" render="detail1" />
</h:inputText>

Related

Primefaces selectOneMenu not displaying initial value

I set up a selectOneMenu with POJOs and a converter, in a p:dialog, see the sources below. It does work, except that initially, when it is first displayed in not-dropped-down state, the first choice is selected, not the one corresponding to the bean value. If I save the state of the selectOneMenu without interacting with it at all, the initially selected first choice is saved and so the real value is overwritten, but if I select a differenct choice, it is saved properly. The bean value to which the selectOneMenu is bound can't be null.
I debugged the converter, and it turned out, that when the backing data is loaded and the dialog is refreshed and displayed, all of the choices go through the converter's getAsString(), plus the choice for the real bean value again. Still, the first choice gets actually selected and displayed in the selectOneMenu. When the dialog's form is commited, the actually selected choice goes through the converter's getAsObject(), regardless whether that was the wrongly selected initial value or the manually selected one.
Please advise what might be the problem.
The xhtml of the button that invokes the dialog, this is in a different form:
<p:commandButton id="toolbarEditButton"
value="Edit selected" update=":editMediaForm"
disabled="#{!contentManager.mediaSelected}"
actionListener="#{contentManager.editSelectedMedia}"
onclick="PF('editMediaWidget').show()" />
The xhtml of the dialog:
<p:dialog id="editMediaDialog" widgetVar="editMediaWidget"
modal="true" resizable="false" >
<h:form id="editMediaForm" >
<p:panelGrid rendered="#{contentManager.isMediaSelected()}" columns="2" >
... <!-- other properties of the selected element -->
<p:outputLabel value="Media type" />
<p:selectOneMenu value="#{contentManager.selectedMedia.mediaType}"
converter="#{mediaTypeConverter}">
<f:selectItems value="#{mediaTypeConverter.allMediaTypes}"
var="mt" itemLabel="#{mt.name}" itemValue="#{mt}" />
<p:ajax listener="#{contentManager.onMediaTypeChanged()}" />
</p:selectOneMenu>
</p:panelGrid>
</h:form>
</p:dialog>
The converter:
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String stringId) {
Long id = Long.valueOf(stringId);
for (MediaType mt : mediaTypes) {
if (mt.getPkid().equals(id)) {
return mt;
}
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object mtObj) {
MediaType mt = (MediaType) mtObj;
return mt.getPkid().toString();
}
public List<MediaType> getAllMediaTypes() {
return mediaTypes;
}
Edit: the backing bean
#SessionScoped // javax.enterprise.context.SessionScoped
#Named("contentManager") // javax.inject.Named
public class ContentManager implements Serializable {
...
private List<Media> mediaList;
private Media selectedMedia = null;
...
public boolean isMediaSelected() {
if (selectedMedia == null) return false;
return true;
}
...
public void saveSelectedMedia() {
myDao.saveMedia(selectedMedia);
}
public void editSelectedMedia() {
// only for debugging, could be removed
}
}
The dialog is brought up and the form is updated by an edit button which is only available after an element is selected from a dataTable (selectedMedia). The update does seem to work, since the other properties of the selected element are properly updated and displayed in the dialog, so the bean value behind the selectOneMenu should be ok.
Update: of course I also examined the generated HTML. The <select> seems to be OK for me, it contains the proper values to be converted by the converter. (The selection is still wrong)
<select id="form:blah_input" name="form:blah_input" tabindex="-1">
<option value="1" selected="selected">1 - half_horizontal</option>
<option value="2">2 - half_vertical</option>
<!-- etc -->
</select>
The objects displayed in the SelectOneMenu have to have proper equals() method, not only the default Object#equals which is only true if they are the same object. This explains why the initial displayed value was always the first: the bean value never matched any of the possible values, so the SelectOneMenu component simply displayed the first one.
So the mistake was not in the JSF or backing bean code, but in the displayed domain objects' (MediaType) code. Adding the equals() method there solved the problem.

Update Action in Bean for JSF

Although it is a simple question . Need an answer for this.
I have written a jsp page as :
<body>
<f:view>
<f:loadBundle basename="message" var="msg"/>
<h:form id="edit">
<h:panelGroup>
<h:selectOneRadio id="CompletePublication" layout="pageDirection">
<f:selectItem itemLabel="SUCCESS" itemValue="true"/>
<f:selectItem itemLabel="FAILED" itemValue="false"/>
</h:selectOneRadio>
</h:panelGroup>
<h:commandButton id="setAction" immediate="true" action="#{user.completePublication}" value="#{msg.Button_OK}"/>
<h:commandButton id="cancel" immediate="true" action="#{user.cancelCompletePublish}" value="#{msg.Button_CANCEL}"/>
</h:form>
</f:view>
</body>
It needs to be handled under theBean:
public class User implements Serializable {
private String name;
private boolean action;
public boolean getAction()
{
System.out.println("Get");
return action;
}
public void setAction(boolean action)
{
this.action=action;
System.out.println("Set");
}
public String completePublication(){
if (action==true){
System.out.println("Value of True Action - " + action);
return "updated";
}
if (action==false){
System.out.println("Value of False Action - " + action);
return "notupdated";
}
return null;
}
public String cancelCompletePublish()
{
System.out.println("Hi");
return null;
}
}
So can any one help on this. At the output evertime i see the "Value of False Action - False"
In your <h:selectOneRadio> you are not passing the value of the selected choice back to your bean when the form is submitted. Therefore, the action variable will never get updated. Assuming that you refer to your managed bean as user in the page, you will need to modify that component by adding the value attribute. Therefore, change
<h:selectOneRadio id="CompletePublication" layout="pageDirection">
to
<h:selectOneRadio id="CompletePublication" value="#{user.action}" layout="pageDirection">
For more information on <h:selectOneRadio> please refer to this link. Also, as mentioned by #Xtreme Biker, you need to understand what immediate="true" does when it is applied to a particular component. For your case, when a user hits any of the <h:commandButton>, the Update Model Phase (as well as other phases) will be skipped. In other words, action will never be set to true when the user selects SUCCESS and then clicks the OK (first) button. That's why you always see Value of False Action - False in your output. To fix this just remove the immediate attribute in the first <h:commandButton> like so
<h:commandButton id="setAction" action="#{user.completePublication}" value="#{msg.Button_OK}"/>
After removing that attribute, make the following change in your completePublication method
public String completePublication(){
if (action){
System.out.println("Value of True Action - " + action);
return "updated";
}
else {
System.out.println("Value of False Action - " + action);
return "notupdated";
}
}
There is no need to return null since action will either be true or false.
NOTE I intentionally did not go into detail on the behavior of the immediate attribute. If you want to understand it, you will need to spend some time to try and understand the JSF lifecycle phases. In fact, you will need to be somewhat comfortable with these concepts as you dive deeper into JSF. Both #johny and #Xtreme Biker gave you some good links to start with. I am copying them below just in case their comments get erased.
Debug JSF Lifecycle
Doubt on immediate attribute for command button

Bean method reading null property from xhtml

I have read a lot of posts at Stackoverflow but I didn't succeed in implementing the belowmentioned problem from my side.
the problem is: I need to type some text in <p:inputTextarea> and when clicking on button I need to get this value in the bean method.
I.e.:
<p:inputTextarea binding="#{input}"/>
<p:commandButton action="#{pessoaMB.adicionarContato(input.value)}" immediate="true"/>
with the bean method:
public void adicionarContato(String value) {
System.out.println(value);
}
The code I'm using gives me a null value.
I'm using #ViewScoped and cannot change this.
First of all, a side note: it is a bad practice to work with JSF components, you should work with model instead. I.e. don't use binding="#{input}", but stick to value="#{bean.text}".
Second, I doubt that immediate="true" is used appropriately in your setup. When used in a UICommand component like <h:commandButton> it will cause to skip JSF lifecycle for components with immediate="false" (or omitted, as it's the default), thus their value won't be set at all. Still, JSF will still preset submittedValue behind the scenes before the action method is executed.
Also, I strongly recommend to read BalusC's blog post Debug JSF lifecycle, as it is more than enlightening on the topic.
As to the solution, I'd suggest to deal with value binding with the bean, as presented in the first comment. With this approach you won't need action method parameter at all. Moreover, rethink your use of immediate attribute. If you think it's correct then you've got two choices: (1) use immediate="true" on <p:inputTextarea> or (2) switch to action="#{bean.action(input.submittedValue)}".
I would've done this :
<h:form>
<p:inputText value="#{pessoaMB.input}"/>
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>
input would be here a pessoaMB property with a getter and setter (an IDE can autogenerate it).
private String input;
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
As for the adicionarContato method, it would be like this :
public void adicionarContato() {
System.out.println(input);
}
You should create a new class, i.e:
public class MyFields(){
String input1;
String input2; //and so on...
//getters and setters
}
Then, in pessoaMB create a property:
private MyFields inputFields; //getter and setter
Finally, in your xhtml file:
<h:form>
<p:inputText value="#{pessoaMB.inputFields.input1}"/>
<p:inputText value="#{pessoaMB.inputFields.input2}"/>
<!-- add more inputText components... -->
<p:commandButton value="add" action="#{pessoaMB.adicionarContato}" />
</h:form>

Input fields hold previous values only if validation failed

I came up with a strange problem. I tried to isolate the problem so following is my simplified code.
public class MyBean {
private List<Data> dataList;
Data selectedData;
public MyBean() {
dataList = new ArrayList<Data>();
dataList.add(new Data("John", 16));
dataList.add(new Data("William", 25));
}
public List<Data> getDataList() {
return dataList;
}
public void edit(Data data) {
selectedData = data;
}
public void newData() {
selectedData = new Data(null, null);
}
public Data getSelectedData() {
return selectedData;
}
public class Data {
String name;
Integer age;
Data(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
xhtml:
<rich:modalPanel id="pop">
<h:form>
Name: <h:inputText value="#{myBean.selectedData.name}" required="true" id="txtName"/><br/>
Age : <h:inputText value="#{myBean.selectedData.age}" required="true" id="txtAge"/>
<a4j:commandButton value="Save"/>
<a4j:commandButton value="Close" onclick="Richfaces.hideModalPanel('pop');return false;"/>
<br/>
<rich:message for="txtName"/><br/>
<rich:message for="txtAge"/>
</h:form>
</rich:modalPanel>
<h:form>
<rich:dataTable value="#{myBean.dataList}" var="data">
<rich:column>#{data.name}</rich:column>
<rich:column>
<a4j:commandLink value="Edit" action="#{myBean.edit(data)}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</rich:column>
</rich:dataTable>
<a4j:commandButton value="New" action="#{myBean.newData()}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</h:form>
This is the path to error:
Load the page
Click the "Edit" link in first row(popup displays)
In popup, clear the "Age" field and click "Save".(Required message shown)
Click cancel(without filling "Age" field)
Click second link.
Now it shows irrelevant data(previous data). - This is the problem
Even when I click "New" button it shows incorrect data.
This happens only if a validation is failed in the popup.
Is there a solution for this?
This problem is in JSF 2 also recognized and explained in detail in the following answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur? If you were using JSF 2, you could have used OmniFaces' ResetInputAjaxActionListener or PrimeFaces' <p:resetInput> or resetValues="true" for this.
To the point, you need to clear the state of the EditableValueHolder component when it's about to be ajax-rendered, but which isn't included in the ajax-execute. To clear the state, in JSF 2 you would have used the convenience method resetValue() for this, but this isn't available in JSF 1.2 and you need to invoke the 4 individual methods setValue(null), setSubmittedValue(null), setLocalValueSet(false), setValid(true) to clear the state.
To figure out which components are to be ajax-rendered, but aren't been ajax-executed, in JSF 2 you would have used PartialViewContext methods for this, but this is not available in JSF 1.2 which hasn't standardized ajax yet. You'd need to fiddle with RichFaces specific ajax API in order to figure that. I can't tell that from top of head, so here's a kickoff example assuming that you already know the components which needs to be cleared. Imagine that the form in your popup has id="popForm" and the name input field has id="nameInput", here's how you could clear it inside the newData() method:
UIInput nameInput = (UIInput) context.getViewRoot().findComponent("popForm:nameInput");
nameInput.setValue(null);
nameInput.setSubmittedValue(null);
nameInput.setLocalValueSet(false);
nameInput.setValid(true);
do one thing on cancel action set all popup values null. now in your next click all values set to be default.
or on click set all previous values null. and set all respective values after that.
I had the same problem. if you are using Primefaces, the solution is as simple as putting resetValues="true" on your p:commandLink or p:commandButton that loads the selected item.
After validation failed if you want to remain same as input data which you have pass as submission parameter, then set value attribute as your form bean name as mention below i.e.
<input type="text" id="fname" path="fname" value="${myFormBean.fname}"/>

JSF commandButton with immediate="true"

I have a situation where there is a selectOneMenu that has a value bound to a backing bean.
I need to have a button that doesn't update model values (that is why it has immediate="true" property).
That button's action method changes the value the selectOneMenu is bound to, but when the page is redisplayed the original value is displayed (the one that was submitted) and not the one set in the action method.
Any ideas why that is happening?
If I didn't explain the problem good enough please let me know.
EDIT:
As requested here is the source code in question:
page code:
<h:selectOneMenu id="selectedPerson"
binding="#{bindings.selectPersonComponent}"
value="#{bean.selectedPerson}">
<s:selectItems var="op" value="#{bean.allPersons}"
label="#{op.osoba.ime} #{op.osoba.prezime}"
noSelectionLabel="#{messages.selectAPerson}">
</s:selectItems>
<f:converter converterId="unmanagedEntityConverter" />
</h:selectOneMenu>
...
<a4j:commandButton action="#{bean.createNew}" value="#{messages.createNew}"
immediate="true" reRender="panelImovine">
</a4j:commandButton>
java code:
private Person selectedPerson;
public String createNew() {
log.debug("New created...");
selectedPerson = null;
bindings.getSelectPersonComponent().setSubmittedValue(null); //SOLUTION
return "";
}
The solution is in the lined marked SOLUTION :)
As it frequently happens a few moments after posting this question I have found an answer:
The cause of the problem is in detail explained here: ClearInputComponents
The problem is (as explained) that model values haven't been updated so the submitted inputs are still in component.submittedValue field and that field is displayed if not empty. It is emptied normally after model has been updated.
The first solution didn't work in my case because there is other important state in the view that mustn't get lost. But the second solution worked great:
component.setSubmittedValue(null);
And that was all that was needed: it is a little extra work because components must be bound to some bean, but not that bad.
To follow up a bit, I don't think you need to bind the component to a bean. You can just grab the component from the FacesContext instance via the UIViewRoot, if you know the component's client ID.
It would go a little something like this:
Foo component = (Foo)FacesContext.getCurrentInstance().getViewRoot().getComponent(clientId);
Where Foo is the class of the component you are using and clientId is the client ID of the component in the "formId:elementId" format that JSF uses.
For me, this has worked:
#ManagedBean(name = "bean")
#ViewScoped
public class Bean {
private SelectOneMenu component;
public SelectOneMenu getComponent() {
return selectComponent;
}
public void setComponent(SelectOneMenu component) {
this.Component = component;
}
public void resetComponent() {
component.resetValue();
}
...
}
<h:selectOneRadio value="#{bean.value}" id = "idRadio" required="true" requiredMessage = "Required Message" binding="#{bean.component}" >
<f:selectItem itemLabel="Value 1" itemValue="value1"/>
<f:selectItem itemLabel="Value 2" itemValue="value2" />
</h:selectOneRadio>
<primefaces:commandButton action="#{bean.resetComponent}" value="Erase" update="idRadio" immediate="true"/>
...
Thanks.

Resources