I have a page to search for authors. It should show the information about the found author or show a message when the author is not found.
I'm trying to use <rich:notifyMessage>, but the problem is that when I use it, the results from the found authors don't appear and, also, the message appear on the right up corner of the page and I'd like it to appear bellow the panel, where the search results would appear.
Look at how I'm doing that, is there a better way to do it?
xhtml
<h:form>
<br />
<br />
Insert Author
<br />
<br />
<br />
<rich:panel id="panel" style="width:310px">
<f:facet name="header">Search for the author you want to insert</f:facet>
<h:panelGrid columns="3">
Name: <h:inputText value="#{insertAuthorController.nameToSearch}" />
<a4j:commandButton value="Search" action="#{insertAuthorController.searchAuthor()}">
</a4j:commandButton>
</h:panelGrid>
</rich:panel>
<br />
<rich:notifyMessage/>
<rich:dataTable value="#{insertAuthorController.authorListOfMap}" var="result">
<c:forEach items="#{insertAuthorController.variableNames}" var="vname">
<rich:column>
<f:facet name="header">#{vname}</f:facet>
#{result[vname]}
</rich:column>
</c:forEach>
</rich:dataTable>
<br />
<h:commandButton value="Go to insert page" action="#{insertAuthorController.searchAuthor()}" />
</h:form>
Bean
public void searchAuthor() {
this.variableNames.clear();
List<String> uris = new ArrayList<String>();
uris = this.authMapper.searchAuthorUriByName(this.nameToSearch);
if( (uris != null) && (!uris.isEmpty()) ) {
for( String uri : uris ) {
Map<String, String> map = new HashMap<String, String>();
String name = this.authMapper.searchNameByAuthorUri(uri);
String email = this.authMapper.searchEmailByAuthorUri(uri);
map.put("URI", uri);
map.put("Nome", name);
map.put("Email", email);
authorListOfMap.add(map);
}
this.addVariableNames();
} else {
FacesContext ctx = FacesContext.getCurrentInstance();
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO,"Detail","Author not found!"); //FacesMessage has other info levels
ctx.addMessage(null,msg);
}
}
Thank you!
The notifyMessage is supposed to behave like that (i.e. pop up in the corner of the screen), if you want just a simple text message use <rich:message>.
Or in this simple case you can check if the result returned something:
<h:outputText value="No results"
rendered="#{fn:length(insertAuthorController.authorListOfMap) == 0}">
Your table doesn't show up because you need to rerender it if you want to see the changes:
<rich:dataTable id="authorsTable" …>
<a4j:commandButton … render="authorsTable" />
Related
We use a p:dataScroller with a LazyDataModel to display products that can be dragged from lazy loaded search results and dropped into a shopping cart.
When more than one chunk of results have been loaded, we are only able to drag/drop items from the most recent chunk of data. If I try to drop an item from the first chunk into my cart, it will incorrectly drop the corresponding item from the most recently loaded chunk in stead.
Example: After the DataScroller has performed 3 lazy loads (3 chunks displayed), if I try to drop the 5th item from the first or second chunk of results, the 5th item from the 3rd chunk of results will be returned by the DragDropEvent.getData() method.
Our Facelets template looks something like this. The droppable element is the sticky header, which is a div with id = headerPanel.
<h:body>
<h:form id="form1">
<p:growl id="msgs" showDetail="true" life="2000">
<p:autoUpdate />
</p:growl>
<h:panelGroup id="headerPanel" layout="block" styleClass="header">
<ui:include src="/WEB-INF/includes/layout/Header.xhtml" />
</h:panelGroup>
<p:droppable for="headerPanel"
scope="shoppingCartAdd"
datasource="productScroller"
hoverStyleClass="dragActive"
tolerance="touch">
<p:ajax listener="#{shoppingCart.addProductToShoppingCart}"
update="shoppingCartButton shoppingCartSidebar" />
</p:droppable>
<ui:include src="/WEB-INF/includes/layout/ShoppingCartBar.xhtml" />
<h:panelGroup id="contentPanel" layout="block" styleClass="content">
<ui:insert name="contentPanel">Content</ui:insert>
</h:panelGroup>
</h:form>
</h:body>
The p:draggable elements are inside a p:dataScroller in a ui-composition that defines the contentPanel from our Facelets template:
<ui:composition template="/WEB-INF/templates/Layout.xhtml">
<ui:param name="title" value="Product Search" />
<ui:define name="contentPanel">
<p:commandButton id="submitButton"
action="#{productSearchBean.searchAction}"
ajax="false"
value="Find All Products" />
<h:panelGrid id="resultsGrid" styleClass="resultsGrid">
<p:dataScroller id="productScroller"
buffer="5"
chunkSize="10"
lazy="true"
rendered="#{productSearchBean.productList.rowCount > 0}"
rowIndexVar="resultIndex"
styleClass="scroller"
value="#{productSearchBean.productList}"
var="rowProduct">
<p:panel id="searchResultsPanel"
header="#{resultIndex + 1} - Product ##{rowProduct.productId}"
closable="true"
toggleable="true"
styleClass="searchResultsPanel">
<h:panelGrid id="productDataGrid" columns="2" columnClasses="thumbnailPanel, textPanel">
<h:panelGroup id="imageDiv" layout="block" styleClass="thumbnailContainer">
<span class="alignmentHelper" />
<p:graphicImage id="thumbnailImage" styleClass="thumbnailImage" value="#{rowProduct.thumbnailUrl}" />
<p:draggable for="thumbnailImage" helper="clone" revert="true" scope="shoppingCartAdd" />
</h:panelGroup>
<h:panelGrid id="textDataGrid" columns="2" columnClasses="padRight, padLeft">
<h:outputText value="id:" /> #{rowProduct.productId}<br/>
<h:outputText value="name:" /> #{rowProduct.productName}<br/>
</h:panelGrid>
</h:panelGrid>
</p:panel>
</p:dataScroller>
</h:panelGrid>
</ui:define>
</ui:composition>
Here's the listener method that gets invoked on a drop event. As mentioned above, the DragDropEvent.getData() method returns the wrong data item if multiple lazy loads have occurred and the user is trying to drag/drop an item from anything but the most recent chunk of data:
public void addProductToShoppingCart(DragDropEvent shoppingCartDropEvent) {
Long draggedId = productIdFromDragDrop(shoppingCartDropEvent);
if (addProductToDefaultShoppingCart(userId, draggedId)) {
fetchShoppingCartProducts();
addSuccessMessage(draggedId);
}
else {
addErrorMessage(draggedId);
}
}
private Long productIdFromDragDrop(DragDropEvent productDroppedEvent) {
Long droppedProductId = null;
Object dropObj = productDroppedEvent.getData();
if (dropObj != null && dropObj instanceof ProductView) {
ProductView view = (ProductView) dropObj;
droppedProductId = view.getProductId();
}
return droppedProductId;
}
Thanks for reading :)
The short version of my problem is that the inputtext will not change the value in bean after I modified the value from the bean.
The longer version:
There is a form in which is a dataTable with user information; some inputTexts, and two buttons. If you fill the inputTexts, a new user will be created with the given data, and appears in dataTable - this works fine, I can create as many users as I can.
The tricky part is if you select a row from the dataGrid, the user information has to appear in the inputText fields - this works fine - so the admin can modify them. But after changing the inputText values in the bean, if the admin changes someting in the inputText, the value "will not follow" tha changes, the value remains the same. What could I do wrong?
The JSF page looks like this:
<html>
<h:body>
<h:form style="font-size:14px;" id="setupform">
...
<p:panel header="Edit users" id="userAddingPanel" rendered="#{settingsbean.validLogin}">
<p:panelGrid columns="2" id="userAddingGrid">
<p:outputLabel value="User Name: " />
<p:inputText id="userName" value="#{settingsbean.userName}" />
<p:outputLabel value="User Password: " />
<p:password id="userPass" value="#{settingsbean.userPassword}" />
<p:outputLabel value="E-mail address: " />
<p:inputText id="userMailAddress" value="#{settingsbean.mailAddress}" />
<p:outputLabel id="userDelete" value="Inactivate User: " />
<p:selectBooleanCheckbox id="isUserDeleted" value="#{settingsbean.deletedUser}" />
<p:commandButton id="addUser" value="Create User" update="userAddingGrid" icon="ui-icon-disk" action="#{settingsbean.addNewUser}" />
<p:commandButton id="modifyUser" value="Modify User" icon="ui-icon-wrench" update="userAddingGrid" action="#{settingsbean.updateUser}" process="setupform"/>
</p:panelGrid>
<br/>
<p:dataTable id="usersTable" var="users" value="#{settingsbean.userList}" tableStyle="overflow: auto;" stickyHeader="true" selectionMode="single" rowKey="#{users.id}" selection="#{settingsbean.selectedUser}">
<p:ajax event="rowSelect" update=":setupform:userName, :setupform:userName,
:setupform:userPass, :setupform:userMailAddress, :setupform:isUserDeleted" />
<p:column headerText="#ID">
<h:outputText value="#{users.id}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{users.loginName}" />
</p:column>
...
</p:dataTable>
</p:panel>
</h:form>
</h:body>
</html>
And my bean looks like this:
#ManagedBean(name ="settingsbean")
#ViewScoped
public class SettingsBean {
private String userName;
private String userPassword;
private boolean deletedUser;
private List<UserDTO> userList;
private UserDTO selectedUser;
/*with getters and setters, what is uncenventional is this setter*/
public void setSelectedUser(UserDTO selectedUser) {
/*if admin selects/unselects a user from dataTable*/
this.selectedUser = selectedUser;
/*if unselect user*/
if(selectedUser == null){
userName = "";
mailAddress = "";
deletedUser = false;
/*if selects user*/
}else {
userName = selectedUser.getLoginName();
mailAddress = selectedUser.getMailAddress();
deletedUser = selectedUser.getDeleted();
}
}
...
public void addNewUser(){
//creates a new user in DB
}
public void updateUser(){
//will update user in DB
}
}
You have to process the components that you want to be updated
<p:commandButton id="modifyUser" value="Modify User" icon="ui-icon-wrench" update="userAddingGrid" action="#{settingsbean.updateUser}" process="userAddingGrid"/>
I am trying to make a form with options to add rows. However, after I type in some input and click the add button again, the input I enter disappears. I'm not sure what is wrong with my code. In addition, when I click the add button, the page refreshes. Is there way to stop this page refresh?
Person.java
public class Person{
private List<String> guys = new ArrayList<String>();
public List<String> getGuys() {
return guys;
}
public void setGuys(List<String> guys) {
this.guys = guys;
public void addNewItem(){
guys.add("");
}
}
form.xhtml
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men">
<h:column>
<p:inputText value="#{men}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton name="submit" type="submit" value="Submit"></h:commandButton>
</h:form>
Provided that the bean is placed in the right scope for the functional requirement, the view scope, the only major mistake left is that you're expecting that the String class has some magic setter method.
It hasn't. The String class is immutable. The following will never work on a String:
<p:inputText value="#{men}" />
You have 2 options:
Create a real model class. You can find complete examples in the following answers:
How to dynamically add JSF components
Recommended JSF 2.0 CRUD frameworks
Set the value by row index instead:
<h:dataTable binding="#{table}" value="#{person.guys}">
<h:column>
<p:inputText value="#{person.guys[table.rowIndex]}" />
</h:column>
</h:dataTable>
(note: no additional bean property necessary for the table! the code is as-is)
This does basically a person.getGuys().add(table.getRowIndex(), submittedValue). I.e. the setter is invoked on the List itself, which works perfectly fine. See also the following related answers concerning ui:repeat:
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values
How map multiple inputText to an array property?
You never update your list, you are just adding empty items. You should do something like this:
Person.java (viewscoped)
public class Person implements Serializable {
private List<String> guys = new ArrayList<String>();
private HtmlDataTable dtGuys;
public void addNewItem() {
guys.add("");
}
public void addToList(ValueChangeEvent e) {
guys.set(dtGuys.getRowIndex(), e.getNewValue().toString());
}
public String save() {
System.out.println("saving...");
for (String item : guys) {
System.out.println("item= " + item);
}
return null;
}
//gettes and setters
}
form.xhtml
<h:form id="frmPrincipal">
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men" binding="#{person.dtGuys}" >
<h:column>
<p:inputText value="#{men}" valueChangeListener="#{person.addToList}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton id="submit" name="submit" value="Submit" action="#{person.save}"/>
</h:form>
Using jsf 2.0.10 and primefaces 3.5
Its because you don't have an scope for that bean, so its request scoped, so when you call the action the bean is created again, you can fix this using a sessionScope or conversationScope
I am using Primefaces AutoComplete and I am getting records from database using Hibernate.
I am able to select values from database when I type in text. What I would like to achieve is when I select a name when I type characters, I would want my other columns in jsf page to get populated. E.g When I select employee name "SMITH" I want employee number, department to get filled with SMITH's employee number and department.
I have the following in jsf page.
<p:autoComplete value="#{myMB.selectedEmployee}"
id="basicPojo" minQueryLength="3"
completeMethod="#{myMB.complete}" var="p"
itemLabel="#{p.empName}"
converter="#{myconverter}"
forceSelection="true" >
<h:outputLabel value="Emp Number" />
<h:outputText value="#{p.employeeNumber}" />
<h:outputLabel value="Department" />
<h:outputText value="#{p.employeeDepartment}" />
</p:autoComplete>
When I select a name, other fields are not getting displayed.
What could be the reason for this? How can I achieve the desired result?
Any help is highly appreciated.
Edit 1
<p:dialog header="Create New Request" style="font-weight:bold"
widgetVar="requestNewDialog" resizable="false"
id="newDlg"
showEffect="fade" hideEffect="fade" appendToBody="true"
modal="true" position="center top" width="850" height="450">
<h:panelGrid columns="2" cellspacing="2">
<h:outputText value="New Employee No:" />
<h:outputText value="" />
</h:panelGrid>
<p:separator />
<p:panelGrid columns="6">
<h:outputLabel value="Employee # " for="emp" />
<p:autoComplete value="#
{myMB.selectedEmployee}"
id="basicPojo" minQueryLength="3"
completeMethod="#{myMB.complete}" var="p"
itemLabel="#{p.longName}"
converter="#{employeeNameConverter}"
forceSelection="true" >
<p:ajax event="itemSelect" update="num"
listener="#{myMB.handleSelect}" />
<h:outputLabel value="Name" for="name" />
<h:outputText value="#{p.employeeNumber}" />
</p:autoComplete>
<h:outputLabel id="num" value="Department" for="dept" />
<p:inputText id="dept" value="#{p.employeeNumber}" >
</p:inputText>
</p:panelGrid>
<p:separator />
</p:dialog>
ManagedBean complete Method
public List<Employee> complete(String query) {
List<Employee> suggestions;
suggestions = new ArrayList<Employee>();
try {
EmployeeQueryData q = new EmployeeQueryData ();
getService().getEmployee(q,query);
employee = q.getResult();
for (Employee p : employee) {
if (p.getEmpName().toLowerCase().contains(query));
suggestions.add(p); //
}
} catch (Exception e) {
}
return suggestions;
}
Use <p:ajax event="itemSelect"...
<p:autoComplete>...
<p:ajax event="itemSelect" update="someOtherFieldId someOtherFieldId2" />
</p:autoComplete>
Migrating from WAS6.1+JSF1.1+richfaces.3.1.5 to WAS7+JSF1.2+facelets1.1.14+richfaces3.3.3.
Error/Status messages are not rendering using h:messages, even though on debugging the facescontext.getMessages() contains the messages.
On submitting a form, I am validating an input. If the validation fails I am adding an error msg to the facescontext. It can be for multiple inputs. Each error msg is added to the facescontext
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
getFacesContext().addMessage(componentID, message);
and on the xhtml I am displaying it using h:messages
I was using jsp in WAS6.1 and JSF1.1 and this used to work fine
Thanks
Adding more details
My xhtml
<ui:composition template="/template.xhtml">
<ui:define name="content">
<div id="content-nosidebar">
<h:form id="uploadDoc1" >
<h:messages/>
<h:panelGrid id="panelGridContact" headerClass="standardPageHeader" width="100%" cellpadding="5">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Upload Contact Info" />
<hr/>
</h:panelGroup>
</f:facet>
<h:panelGroup id="msgId">
<xyz:errorMessages />
<xyz:statusMessages />
</h:panelGroup>
<h:panelGrid style="text-align: center;font-weight: bold;">
<h:outputText value="Click on Browse button to identify CSV file with contact information for upload."/>
<h:outputText value="File size limit is 10MB."/>
<h:panelGroup>
<rich:fileUpload id="fileuploader" fileUploadListener="#{uploadContactCntrl.onSubmit}"
acceptedTypes="csv" allowFlash="true" listHeight="50" addControlLabel="Select File" uploadControlLabel="Submit" clearControlLabel="clear"/>
</h:panelGroup>
<h:outputText value=" "/>
</h:panelGrid>
</h:panelGrid>
</h:form>
</div>
</ui:define>
</ui:composition>
errorMessages and statusMessages are common tags to display error(validation error) and status((like Update complete) messages
In the the backingbean on submit if an error is encountered (like "File not found" or "Database is down" I call a common method with the error/status message from the resource file.
WebUtils.addCustomErrorMessage("global.error.ContactInfo-DuplicateRecords-UserID", new String[]{userid,Integer.toString(j+1)}, Constants.RESOURCE_BUNDLE_NAME);
or
WebUtils.addCustomStatusMessage("global.error.ContactInfo-successMessage", new String[]{Integer.toString(noOfRowsInserted)}, Constants.RESOURCE_BUNDLE_NAME);
public static void addCustomErrorMessage(String msg, String componentID) {
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
getFacesContext().addMessage(componentID, message);
}
public static void addCustomStatusMessage(String msg, String componentID) {
if (errorCodeParameters != null && errorCodeParameters.length > 0)
msg = MessageFormat.format(msg, (Object[])errorCodeParameters);
FacesMessage message = new FacesMessage();
message.setDetail(msg);
message.setSummary(msg);
message.setSeverity(FacesMessage.SEVERITY_INFO);
getFacesContext().addMessage(componentID, message);
}
We also use the same tags to display an error message when an error is encountered on an input field. For e.g. a Firstname field has invalid characters.
As mentioned earlier, this was working fine before we migrated to JSF1.2
Your answer need to have xhtml code too, any way i'm giving u sample for using validation in JSF 1.2...
The xhtml code should be like..
<h:inputText id="txt_project_name"
value="#{FIS_Project_Master.txt_project_name_value}"
validator="#{FIS_Project_Master.txt_project_name_validator}"/>
<h:message id="msg_txt_project_name" for="txt_project_name" />
The java code should be like...
public void txt_project_name_validator(FacesContext context, UIComponent component, Object value) {
if (bmwpProjectMstFacade.ispmProjName_exists(value.toString().toUpperCase().trim())) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Warning", "Project Name Already Exist");
throw new ValidatorException(message);
}
}