I'm a newbie with JSF so it's really possible that my question is stupid ;-)
I must create a rich:toolTip with "mode=ajax" and I need to send a parameter to my Bean to be able to find the data displayed in the tooltip.
I have tried to do that with but it's not working.
This is my code:
<h:outputText value="#{resultPrestationBean.mainPanelViewOne.data}" id="anId">
<rich:tooltip mode="ajax" showDelay="250">
<a4j:actionparam id="test2" value="MyValue" assignTo="#{resultPrestationBean.test2}"/>
<f:facet name="defaultContent">
<f:verbatim>Loading...</f:verbatim>
</f:facet>
<h:outputText value="info #{resultPrestationBean.test}" />
</rich:tooltip>
</h:outputText>
And this is the code in my ResultPrestationBean
public String getTest() {
return "Blabla " + this.test2;
}
public void setTest2(String test2) {
this.test2 = test2;
}
public void test2(String test2) {
this.test2 = test2;
}
And the result in my tooltip is always "info Blabla null"
If I use the Net panel in Firebug, I see the parameter in the POST...
Could you explain me?
I don't believe you can send an actionparam without an action. I tried this out and was able to get it working by creating a a4j:jsFunction and putting the parameter inside it. This jsFunction would then be called on the onshow event of the tooltip. BTW, I'm using richfaces 4.
<rich:tooltip id="tool1" mode="ajax" showDelay="500" layout="block" followMouse="false" onshow="send();">
<h:outputText id="tool" value="New Entry #{timesheetHome.rowNum}" />
</rich:tooltip>
<a:jsFunction name="send" render="tool">
<a:param name="x" value="5" assignTo="#{timesheetHome.rowNum}"></a:param>
</a:jsFunction>
Related
So I'm trying to nest a datatable within another datatable in the rowexpansion tag as follows:
<h:form>
<p:dataTable var="item"
value="#{bean.items}">
<p:column>
<p:rowToggler/>
</p:column>
<p:column headerText="Item Name">
<h:outputText value="#{item.name}"/>
</p:column>
<p:rowExpansion>
<p:dataTable var="subitem"
value="#{item.subitems}">
<p:column headerText="Subitem Name">
<h:outputText value="#{subitem.name}" />
</p:column>
<p:column>
<p:splitButton value="Save" action="#{bean.save}">
<p:menuitem value="Update" action="#{bean.update}"/>
<p:menuitem value="Delete" action="#{bean.delete}"/>
</p:splitButton>
</p:column>
</p:dataTable>
</p:rowExpansion>
</p:dataTable>
</h:form>
the testing methods in the bean are just
public void save() {
addMessage(FacesMessage.SEVERITY_INFO, "Success!", "Saved subitem");
PrimeFaces.current().ajax().update(":frmTopbar");
}
public void update() {
addMessage(FacesMessage.SEVERITY_INFO, "Success!", "Updated subitem");
PrimeFaces.current().ajax().update(":frmTopbar");
}
public void delete() {
addMessage(FacesMessage.SEVERITY_INFO, "Success!", "Deleted subitem");
PrimeFaces.current().ajax().update(":frmTopbar");
}
public void addMessage(FacesMessage.Severity severity, String summary, String detail) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, summary, detail));
}
If only a single item and its subitems is loaded, everything displays and splitbutton buttons work fine.
The bean just sends a FacesMessage to test and like I said, the message is properly shown for each of the 3 buttons.
But as soon as I load 2 or more items and their subitems, everything looks visually correct, but the commands in splitbutton no longer reach bean, so no FacesMessage is sent.
Does anyone have a clue about what is going on or a suggestion as to what can be done to fix it?
I'm using primefaces v11.0
Thanks a lot!
I seem to have found a workaround with p:remoteCommand using BalusC's tips.
So what I've done, is place this somewhere in my page that will map a javascript function to a bean method.
<p:remoteCommand name="splitButtonMenuitemClicked" actionListener="#{bean.save}" style="display: none;" />
I then place this jquery code in my page to catch the click event from any split button:
jQuery( document).delegate( ".ui-splitbuttonmenu .ui-menuitem-link", "click",
function(e){
var menuitemText = $(this).find("span.ui-menuitem-text");
var itemText = $(menuitemText).text();
splitButtonMenuitemClicked([{ name: "fooName", value: itemText }])
}
);
Now in my bean function, I just retrieve my parameter as follows:
public void save() {
String fooName= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("fooName");
//fooName is unique key in may table, so it works well to work on the correct entity
...
}
It'll do for now, although it would be nice if the components worked as one hopes.
I am using Java EJB with JSF.
What I doing is just a simple search result from database and display it on a table using JSF with ajax. But why when first submitting, the result is not appear. And second time only the result will appear.
Below is my JSF page code
<h:form id="wholeForm">
<p:panelGrid id="resultTable" styleClass="result_table1" >
<p:row>
<p:column>
<div align="center" id="font-size1">
<h:selectOneRadio value="#{scanResult.typeOfScan}">
<f:selectItem itemValue="Carrier" itemLabel="Carrier"></f:selectItem>
<f:selectItem itemValue="Slot" itemLabel="Slot"></f:selectItem>
<f:selectItem itemValue="HD" itemLabel="HD"></f:selectItem>
<p:ajax event="change"></p:ajax>
</h:selectOneRadio>
Scan: <p:inputText styleClass="searchField" id="counter" value="#{scanResult.serialNumber}" a:autofocus="true">
<p:ajax event="keydown" update="wholeForm" onstart="if (event.keyCode != 13) { return false;}" listener="#{scanResult.checkResult()}" />
</p:inputText>
<br/><br/>
</div>
</p:column>
</p:row>
</p:panelGrid>
<p:panelGrid id="resultTable1" styleClass="result_table1" rendered="#{not empty scanResult.scanResultCarrier}" >
<c:forEach items="#{scanResult.scanResultCarrier}" var="result" >
<!-- ..do something and call out result -->
</p:column>
</p:row>
</c:forEach>
</p:panelGrid>
</h:form>
And my managed bean is as below
#Named(value = "scanResult")
#SessionScoped
public class scanResult implements Serializable {
//Some code here
public void checkResult() {
scanResultCarrier = new ArrayList<>();
scanResultSlot = new ArrayList<>();
System.out.println("checking");
if (typeOfScan.equals("Carrier")) {
System.out.println("Serial " + serialNumber);
scanResultCarrier = scanresultcarrierFacade.searchResultCarrier(serialNumber);
System.out.println(scanResultCarrier.size());
} else if (typeOfScan.equals("Slot")) {
scanResultSlot = scanresultslotFacade.searchResultSlot(serialNumber);
} else if (typeOfScan.equals("HD")) {
} else {
}
serialNumber = "";
}
}
I use System.out.println(lsitofresult.size()); to print out my result and the result is not blank. Mean that I successful retrieve my result from database.
But my result table not able to show out after I click on enter.
Then I notice that my url is as below
http://localhost:8080/outgoingScanSystem-war/faces/index.xhtml;jsessionid=8b6cefa932ff60984607ee38ec13
And after I refresh my page, the result will appear again.
And my url change to :
http://localhost:8080/outgoingScanSystem-war/faces/index.xhtml
May I know why? Is it related to URL? I have no idea where should I start my troubleshoot. Anyone can give me some guideline?
I see some problems here. First of all, you're using the session scope while your managed bean should be view scoped (there's no reason to use the session here, see the link below). That's the cause why your results are getting displayed when you refresh the page.
Second, I'd rather put the search results out from the form. I see no reason for them to be in the same form of the search itself. Then, when performing a searh you should only update the result list:
<p:ajax event="keydown" update="resultTable1" onstart="if (event.keyCode != 13) { return false;}" listener="#{scanResult.checkResult()}" />
Third, as you're using Primefaces, I encourage you to take a look to its p:remoteCommand tool in order to perform ajax-based calls to the beans from your JS code directly. This way you should avoid your second problem, which seems to be that you're preventing the standard form sending on the ajax start event (which might not even get called). You could do something like this:
<p:remoteCommand name="search" update="resultTable1" actionListener="#{scanResult.checkResult}" />
<p:inputText styleClass="searchField" id="counter" value="#{scanResult.serialNumber}"
a:autofocus="true" onkeypress="if (event.keyCode != 13) {search(); return false;}">
<!-- Update the input text value in the bean for each pressed key -->
<p:ajax event="keydown" />
</p:inputText>
See also:
How to choose the right bean scope?
Jsf calling bean method from input text when pressing enter
I created a very simple example based on my project in order to illustrate my doubt. Just a way to register a person with a list of telephone numbers.
MainController.java
private String name;
private List<Phone> phoneList;
// Getters and Setters
#PostConstruct
private void init() {
phoneList = new ArrayList<>();
}
public static class Phone implements Serializable {
private String number;
// Getters and Setters
#Override
public String toString() {
return number != null ? number : "null";
}
}
public void add() {
phoneList.add(new Phone());
}
public void save() {
System.out.println("Name: " + name + "; " + phoneList.toString());
}
index.xhtml
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
In my example, note that all phone fields that are added MUST be filled in (required = true).
The problem is: when I type name and click add (to add a phone) the value of the field is maintained. But when I type a first phone and click add, the phone's value is not maintained. This occurs for all fields within the component ui:repeat.
Is there a way to preserve the input values within a after an immediate request, as with the name field?
Extra note: Other strange behavior I noticed is when add at least two phone fields, let the first blank and fills the second, and saves the form. After a failed validation (due to phone blank), click add will make all fields are filled with the value of the second phone.
Wildfly 9.0.2, JSF Api (Jboss) 2.2.12
Thanks to #BalusC comment. The OmniFaces library has two taghandlers that can be used in this case. In both cases input values will be preserved in case of validation failure. Note that h:commandButton should be with <h:commandButton immediate="false" />.
ignoreValidationFailed
In this case all validation failures will be ignored (including converter failures). Note that the h:form have to be changed to o:form. Also, the failures messages will still be displayed, which can be solved putting a proper condition in the rendered attribute. The files will look like this:
index.xhtml
<o:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:ignoreValidationFailed />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</o:form>
<h:messages rendered="#{facesContext.validationFailed}" />
skipValidators
In this case only the validation failures will be ignored (the converters will still run). The failures messages will not be displayed, except for the converters. Note that this taghandler is only available since the 2.3 version. The files will look like this:
index.xhtml
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:skipValidators />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
The solution that I use to this problem is to create an external field to the loop, which stores a JSON containing the values that should be saved. This field, to be outside the loop, properly saves values after each try and restore the missing values when necessary. I use two functions JavaScript and JQuery library.
So the files would look like this:
index.xhtml
<h:outputScript library="jquery" name="jquery.min.js" />
<h:outputScript library="all" name="all.js" />
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText styleClass="savePhoneNumber" value="#{phone.number}" required="true" onchange="saveUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')" />
</ui:repeat>
<h:inputHidden id="allPhoneNumber" binding="#{allPhoneNumber}" />
<h:outputScript>loadUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')</h:outputScript>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
all.js
function saveUiRepeatInput(inputAll, inputClass) {
document.getElementById(inputAll).value = JSON.stringify($('.' + inputClass).map(function() { return this.value; }).get());
}
function loadUiRepeatInput(inputAll, inputClass) {
var jsonAll = document.getElementById(inputAll).value;
if (jsonAll) {
var array = JSON.parse(jsonAll);
$('.' + inputClass).each(function(i) { if (i < array.length) this.value = array[i]; });
}
}
Although work perfectly (including via ajax, with some minor changes), it looks like a hack, not an ideal solution. So if anyone can help with any solution strictly based on JSF, I will be grateful. Thanks.
I have a h:inputText with valueChangeListener, when the user type some code another h:inputText display data from MySQL about that code, the valueChangeListener works but the second h:inputText not displayed the value and only do it when I set the readonly attribute or I change the component to h:outputText
my facelets page is:
<h:form id="idFacturacion">
<rich:panel>
<f:facet name="header">
<h:outputText value="FACTURACION AL CLIENTE" />
</f:facet>
<h:panelGrid columns="4">
<h:outputText value="Cedula: " />
<h:inputText value="#{facturaBean.encFactura.cedula}" onchange="submit();" valueChangeListener="#{facturaBean.processValueChange}" />
<h:outputText value="Nombre: " />
<h:inputText value="#{facturaBean.encFactura.nombre_cli}" />
</h:panelGrid>
</rich:panel>
</h:form>
facturaBean is:
#ManagedBean
#SessionScoped
public class FacturaBean {
private EncFactura encFactura = new EncFactura();
//getter and setter
public void processValueChange(ValueChangeEvent event){
String ced = event.getNewValue().toString();
try{
//do the database thing
if(resultSet.next()){
encFactura.setNombre_cli(resultSet.getString("nombre_cli"));
}else{
encFactura.setNombre_cli("");
}
}catch(SQLException error){
facesContext.addMessage(null, new FacesMessage("Hubo un error SQL."));
}
}
}
Please see
Change inputText value from listener method… and
Possible to execute `valueChangeListener` for `p:inputText` without hitting `enter` key?
May I suggest using ajax?
Here is a primefaces example but you could apply to richfaces..
<h:inputText value="#{facturaBean.stringOne}" >
<p:ajax event="change" listener="#{facturaBean.processValueChange}" update="strTwo"/> </h:inputText> <h:outputText value="Nombre: " />
<h:inputText id="strTwo" value="#{facturaBean.stringTwo}" />
</h:panelGrid>
private String stringOne= "";
private String stringTwo= "";
public void processValueChange(){
stringTwo = stringOne;
}
With getters etc.. basically on change, fires off to ajax, you do your database call etc, then it returns the response and updates your other input field, it's a much cleaner way than trying to submit forms etc..
Also are you sure you want session scope?
I've been using JSF for a while but there's something that has always confused me. Hopefully someone can help.
Simple example, there's a page that shows a table of "Person"s and when you click on the "Person" name, it takes you to a page to view the details of the "Person".
Typically, I implement a personSearch.jsf page like this:
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink action="#{personHandler.show( person.id )}" >
<h:outputText value="#{person.name}" />
</h:commandLink>
</h:column>
</h:dataTable>
And I implement a personView.jsf page like this:
<h:panelGrid columns="2">
<h:outputText value="Person ID:" />
<h:outputText value="#{personHandler.selectedPerson.id}" />
<h:outputText value="Person Name:" />
<h:outputText value="#{personHandler.selectedPerson.name}" />
</h:panelGrid>
PersonHandler.show(Integer personId) sets personHandler.selectedPerson and then redirects to the personView page.
This all works fine when PersonHandler is a session bean. But I prefer it to be a request scoped bean because the user may have several windows open and I don't want there to be only one selected person per session.
So my question is, what's the "correct" way to do this JSF? I was once able to get what I wanted using a4j:keepAlive on the personHandler, but that always felt like a kludge. Again, this is something I've never understood about JSF.
Any help is greatly appreciated!
rob
If the view is supposed to be bookmarkable, pass the person ID as a GET request parameter instead of a POST request "parameter".
<h:outputLink value="viewperson.xhtml">
<f:param name="id" value="#{person.id}" />
</h:outputLink>
This way you can use two #RequestScoped beans, one for the list and one for the view. You can preload the selected person as follows:
#ManagedProperty(value="#{param.id}")
private Long id;
#PostConstruct
public void init() {
selectedPerson = personDAO.find(id);
}
If it is not supposed to be bookmarkable, then just create a single view which renders the view state conditionally.
<ui:fragment rendered="#{!personHandler.viewMode}">
<h:form>
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink value="#{person.name}" action="#{personHandler.show(person)}" />
</h:column>
</h:dataTable>
</h:form>
</ui:fragment>
<ui:fragment rendered="#{personHandler.viewMode}">
<h:form>
...
<h:commandLink value="Go back" action="#{personHandler.back}" />
</h:form>
</ui:fragment>
(You can if necessary split out the content of the both framgents to another Facelet files which you include by <ui:include>)
This way you can use a single #ViewScoped bean with action methods returning void or null.
public void show(Person selectedPerson) {
this.selectedPerson = selectedPerson;
}
public void back() {
selectedPerson = null;
}
public boolean isViewMode() {
return selectedPerson != null;
}
You can even wrap the whole view in some
<h:panelGroup id="container">
and nest the following in both command links to let Ajax magic do the work
<f:ajax execute="#form" render=":container" />