I have a very strange problem with JSF, but I cannot solve it on my own, because there is no error message I can google for. The problem is, that I have one view for submitting a new article or updating an existing article.
The method getArticle() returns - if ?id=x is set via url - the article POJO with the id of x. Otherwise a pure empty new article. Depending of id is set, the mode editArticle is set to true or false.
So if I pass an id via URL, the form changes to "Update article" and the values of the article are shown. But if I hit the submit button, nothing happens. No output, no error. Using HTTP Live Headers in Firefox, I see a request to the server. Looking with wireshark on the loopback interface, there is traffic, too.
But on the other hand, the "Create new article"-Button (if id is not set) without a problem.
The environment: JSF 2.2, Apache Tomcat 7/8, Java 7/8, Windows/Ubuntu (tried different envs, but always the same, so it seems to be a problem "by design" :-) ). Tried also renaming methods, calling via ActionListener, changing the order of the panelGrids... but no way. The method updateArticle() of the bean is never called by hitting the button.
<h:form id="idMasterForm" enctype="multipart/form-data">
<h:panelGroup rendered="#{userController.loggedIn}">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="title" value="Title" />
<p:inputMask id="title"
value="#{editArticleController.article.title}" />
<p:outputLabel for="author" value="Author" />
<p:inputText id="author" value="#{userController.id}"
readonly="true" />
<p:outputLabel for="date" value="Date" />
<p:inputMask id="date"
value="#{editArticleController.article.date}" readonly="true" />
<p:outputLabel for="link" value="File" />
<p:selectOneMenu id="link"
value="#{editArticleController.article.link}">
<f:selectItems value="#{uploadFilesController.filesItems}" />
</p:selectOneMenu>
<p:outputLabel for="editor" value="" />
<p:editor id="editor" widgetVar="editorWidget"
value="#{editArticleController.article.text}" width="600" />
</h:panelGrid>
<h:panelGrid columns="2" style="margin-top: 10px" rendered="#{!editArticleController.editArticle}">
<p:commandButton value="Submit new article"
action="#{editArticleController.createArticle()}"
icon="ui-icon-disk" />
<p:commandButton value="Clear" type="button"
onclick="PF('editorWidget').clear();" icon="ui-icon-close" />
</h:panelGrid>
<h:panelGrid columns="2" style="margin-top: 10px" rendered="#{editArticleController.editArticle}" >
<p:commandButton value="Update article"
action="#{editArticleController.updateArticle()}"
icon="ui-icon-disk" />
<p:commandButton value="Clear" type="button"
onclick="PF('editorWidget').clear();" icon="ui-icon-close" />
</h:panelGrid>
<h:outputText rendered="#{ ! userController.loggedIn}"
value="#{res.globNotLoggedIn}" />
</h:panelGroup>
</h:form>
And here is the Managed Bean:
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import hwr.Util;
import hwr.g2.model.Archive;
import hwr.g2.model.Article;
import hwr.g2.model.Author;
import hwr.user.UserController;
#ManagedBean
public class EditArticleController {
private Article article;
private Boolean editArticle;
private Integer editArticleID;
public EditArticleController() {
this.article = new Article();
System.out.println("EditArticleController was called");
}
public Article getArticle() {
//System.out.println("getArticle() was called");
if (this.getEditArticle()) {
this.article = new Article(this.editArticleID);
}
return this.article;
}
public void setArticle(Integer articleID) {
this.article = new Article(articleID);
}
public void setArticle(Article article) {
System.out.println("setArticle(Article article) was called");
this.article = article;
}
public void setText(String text) {
this.article.setText(text);
}
public String getText() {
return this.article.getText();
}
public void setTitle(String title) {
this.article.setTitle(title);
}
public String getTitle() {
return this.article.getTitle();
}
public Boolean getEditArticle() {
// https://stackoverflow.com/questions/550448/get-request-and-session-parameters-and-attributes-from-jsf-pages
HttpServletRequest req = (HttpServletRequest) FacesContext
.getCurrentInstance().getExternalContext().getRequest();
try {
this.editArticleID = Integer.valueOf(req.getParameter("id"));
if (this.editArticleID > 0) {
this.setEditArticle(true);
} else {
this.setEditArticle(false);
}
} catch (Exception e) {
this.setEditArticle(false);
}
return editArticle;
}
public void setEditArticle(Boolean editArticle) {
this.editArticle = editArticle;
}
public Date getActualDate() {
Date d = new Date();
return d;
}
public void rangChanged() {
// nothing
}
public String createArticle() {
System.out.println("New Article...");
Util util = new Util();
UserController user = (UserController) util.getBean("userController");
this.article.setAuthor(new Author(user.getId()));
this.article.setDate(new Date());
try {
Archive archive = new Archive();
archive.addArticle(this.article);
} catch (Exception e) {
System.out.println("something goes wrong here...");
e.printStackTrace();
}
return "g2_home?faces-redirect=true";
}
public String updateArticle() {
System.out.println("*** Update Article... ***");
System.out.println("Debug: Update article, ID "
+ this.article.getId() + "! title: " + this.article.getTitle()
+ " and text: " + this.article.getText()
+ " and written by "
+ this.article.getAuthor().getFirst());
try {
Archive archive = new Archive();
archive.updateArticle(this.article);
} catch (Exception e) {
System.out.println("something goes wrong here...");
e.printStackTrace();
}
return "g2_home?faces-redirect=true";
}
}
I used a checklist of BalusC (action method is not called in JSF), but didn't found something.
It whould be really great, if someone can point me in the right direction. By the way, is there an better way to fill the form? In my kind of way, the method getArticle() is called several times by the view.
I Think you should define the managed bean scope #ViewScoped or any other scope you want .
look at this question [question] : What is the default Managed Bean Scope in a JSF 2 application?
If you don't set the scope for the bean, it will be #RequestScoped by default, which means the bean will be re created per user request. Change it to #ViewScoped at least in order for the bean to keep alive while the user is interacting with the same view in multiple requests (e.g. ajax requests).
#ManagedBean
#ViewScoped
public class EditArticleController {
//rest of class definition
}
Related
I am using JSF 2.2.20. In the xhtml page, there is one input text field and a file upload (advanced mode) . But my problem is, while listener is called for file-upload, the input text is coming as empty. How can I get the input text? Help me out.
xhtml code snippet:
<h:form id="formID" enctype="multipart/form-data" method="post">
<p:growl id="growlId" sticky="true" showDetail="true"><p:autoUpdate /></p:growl>
<p:outputPanel id="DocInfo">
<h:panelGrid id="DocGrid" columns="3" style="margin-bottom:10px" cellpadding="8">
<p:outputLabel for="upload_Doc_Name" value="Document Name :* " />
<p:inputText id="upload_Doc_Name" value="#{uploadDocManagedBean.uploadDocName}" style="font-size:8pt;width:230px" />
<p:outputLabel for="projectUploadDocId" value="Choose File :* " style="font-weight:bold; float:left" />
<p:fileUpload id="projectUploadDocId" value="#{uploadDocManagedBean.uploadedFile}" mode="advanced" dragDropSupport="true"
listener="#{uploadDocManagedBean.fileUploadListener}" />
<br/>
</h:panelGrid>
</p:outputPanel>
</h:form>
The managed bean code snippet:
#ManagedBean(name = "uploadDocManagedBean")
#ViewScoped
public class UploadDocManagedBean implements Serializable {
private static final long serialVersionUID = -1L;
private String uploadDocName;
private UploadedFile uploadedFile;
public String getUploadDocName() {
return uploadDocName;
}
public void setUploadDocName(String uploadDocName) {
this.uploadDocName = uploadDocName;
}
public UploadedFile getUploadedFile() {
return uploadedFile;
}
public void setUploadedFile(UploadedFile uploadedFile) {
this.uploadedFile = uploadedFile;
}
public void fileUploadListener(FileUploadEvent fileUploadEvent) {
try {
uploadedFile = fileUploadEvent.getFile();
String filename = uploadedFile.getFileName();
if (uploadDocName == null || uploadDocName.isEmpty()) {
String msg = "Document Name is empty.";
FacesContext.getCurrentInstance().addMessage("growlId",
new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg));
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
In the managed bean, the uploadDocName is the coming as empty everytime, while this fileUploadListener() method is called.
What am I missing here?
You can define process attribute on fileUpload. To make it simple, try with process="#form", it should work ;) By default, only fileUpload client id e.g #this is sent to the server for processing
More details for fileUpload component, see here: https://primefaces.github.io/primefaces/11_0_0/#/components/fileupload
This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 6 years ago.
i m working on a login jsf and hibernate application , i have a problem, whan i click on login button nothing happens
<h:head></h:head>
<body>
<h:form>
<h:outputText value="#{accountController.message}" escape="false"> </h:outputText>
</h:form>
<h:panelGrid columns ="2" cellpadding="2" cellpacing="2">
<h:outputText value="Username"></h:outputText>
< h:inputText value="#{utilisateursController.utilisateurs.username}"> </h:inputText>
<h:outputText value="Password"></h:outputText>
<h:inputSecret value="#{utilisateursController.utilisateurs.password}"></h:inputSecret>
<h:commandButton value = "login" action="#{utilisateursController.login()}" ></h:commandButton>
UtilisateursController.java
package controller;
import javax.faces.bean.*;
import entities.*;
import model.UtilisateursModel;
import java.util.*;
#ManagedBean(name="UtilisateursController")
#SessionScoped
public class UtilisateursController {
private UtilisateursModel utilisateursModel = new UtilisateursModel();
private Utilisateurs utilisateurs = new Utilisateurs();
private String message = "";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Utilisateurs getUtilisateurs() {
return utilisateurs;
}
public void setUtilisateurs(Utilisateurs utilisateurs) {
this.utilisateurs = utilisateurs;
}
public String login(){
if(utilisateursModel.login(this.utilisateurs.getUsername(),
this.utilisateurs.getPassword())!=null){
return "welcome";
} else {
this.message = "Utilisateur invalid";
this.utilisateurs = new Utilisateurs();
return "login";
}
}
}
UtilisateursModel.java
package model;
import org.hibernate.Query;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import entities.*;
public class UtilisateursModel extends AbstractModel<Utilisateurs>{
public UtilisateursModel(){
super(Utilisateurs.class);
}
public Utilisateurs login(String username, String password){
try{
if (!(sessionFactory.getCurrentSession().getTransaction().getStatus() != TransactionStatus.ACTIVE) )
sessionFactory.getCurrentSession().getTransaction().begin();
Query query = sessionFactory
.getCurrentSession()
.createQuery(
"from utilisateurs where username=:username and password=:password");
query.setString("username", username);
query.setString("password", password);
return (Utilisateurs)query.uniqueResult();
} catch(Exception e){
return null;
}
}
}
thank you for your help , i really don t see anything wrong on the code
You cannot execute an action when the command button is outside a form. Change your code to the following:
<h:form>
<h:outputText value="#{accountController.message}" escape="false"> </h:outputText>
<h:panelGrid columns ="2" cellpadding="2" cellpacing="2">
<h:outputText value="Username"></h:outputText>
<h:inputText value="#{utilisateursController.utilisateurs.username}"/>
<h:outputText value="Password"/>
<h:inputSecret value="#{utilisateursController.utilisateurs.password}"/>
<h:commandButton value = "login" action="#{utilisateursController.login()}" />
</h:panelGrid>
</h:form>
Hope this works out for you!
You need to change some code as per following
You need to put all element inside form body like all inputs and
submit button
You need to change your manage bean name
utilisateursController instead of UtilisateursController
I means
#ManagedBean(name="utilisateursController") instead of #ManagedBean(name="UtilisateursController")
Hope you will fix your problem!
I have a jsf page that has 2 parts: a table displaying a list of records and a dialog to add a new record. I added some validation features but I can't get them to work properly.
I need it to:
1) Validation error not appear the first time dialog shows up
2) If any validation error happens, keep it open and show error messages.
3) If no validation error and back-end executed successfully, update the table.
This is what I have:
<h:body>
<h:form id="form01">
<p:dataTable id="tbl1" value="#{welcomeController.teams}" var="team" >
<p:column headerText="Id">
<h:outputText value="#{team.seq}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{team.name}" />
</p:column>
</p:dataTable>
<p:dialog id="teamDialog" closable="false" visible="#{welcomeController.addMode}"
widgetVar="teamDialog_w" modal="true" resizable="false" draggable="true"
header="New Team Detail">
<p:messages />
<p:panelGrid columns="2">
<h:outputText value="Name" />
<p:inputText id="name" value="#{welcomeController.newTeam.name}" />
</p:panelGrid>
<p:commandButton value="Submit" ajax="true" actionListener="#{welcomeController.addNewTeam}"
update=":form01"oncomplete="teamDialog_w.hide(); console.log(args);" />
</p:dialog>
<p:commandButton value="ADD" actionListener="#{welcomeController.startAdd}"
oncomplete="teamDialog_w.show(); console.log(args);" update="teamDialog" />
</h:form>
The bean:
#Named
#ConversationScoped
public class WelcomeController implements Serializable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final long serialVersionUID = 1L;
private List<TeamDto> teams;
#Inject SessionManager sessionMan;
#Inject DatabaseUtil dbCache;
#Inject TeamService teamService;
#Inject Conversation conversation;
private TeamDto newTeam = new TeamDto();
private boolean addMode = false;
public List<TeamDto> getTeams() throws IOException {
if (teams == null || teams.size() == 0) {
teams = teamService.getAll();
}
return teams;
}
public void setTeams(List<TeamDto> teams) {
this.teams = teams;
}
public void reload() {
conversationBegin();
}
public void conversationBegin() {
if (conversation.isTransient()) {
conversation.begin();
}
}
public void conversationEnd() {
if(!conversation.isTransient()){
conversation.end();
}
}
public void startAdd() {
reload();
newTeam = new TeamDto();
addMode = true;
}
public TeamDto getNewTeam() {
return newTeam;
}
public void setNewTeam(TeamDto newTeam) {
this.newTeam = newTeam;
}
public void addNewTeam() throws IOException, ValidatorException {
if (newTeam.getName().isEmpty()) {
sessionMan.addGlobalMessageFatal("INVALID INFO", null);
return;
}
teamService.addTeam(newTeam);
teams.add(newTeam);
newTeam = new TeamDto();
addMode = false;
}
public boolean isAddMode() {
return addMode;
}
public void setAddMode(boolean addMode) {
this.addMode = addMode;
}
}
I have 2 problems here:
1) After I submit an empty string, I expect the dialog to still open (because addMode is true) but it's not. Why is it?
2) If I put the "ADD" button like this:
<p:commandButton value="ADD" actionListener="#{welcomeController.startAdd}" oncomplete="teamDialog_w.show(); console.log(args);" >
<f:ajax render="teamDialog" />
</p:commandButton>
at least when I open the dialog again, I can see the error message. But in my code, I can't see the error message. Why is it so? Aren't they equivalent?
Is there anything wrong with my understanding?
Please help. Thank you very much.
Dialogs should operate with their own form in JSF, this is crucial.
To prevent your dialog from closing on validation you can use in Primefaces :
if (args &&
!args.validationFailed){PF('eventDialog').hide();}
like this:
<p:commandButton value="ADD"
actionListener="#{welcomeController.startAdd()}"
oncomplete="if (args && !args.validationFailed){PF('teamDialog').hide();}"
update="your_dialog_formID:messages, other_updated_IDs" />
here
if (args && !args.validationFailed){PF('teamDialog').hide();}
you can obvoiusly add else clause and do #3 "If no validation error and back-end executed successfully, update the table."
here BalusC gives great explenation why:Keep p:dialog open when a validation error occurs after submit
Using Apache MyFaces JSF 2.0.
XHTML code:
<h:form id="searchUser" prependId="false">
<h:selectManyListbox value="#{listManyBean.listUser}" id="userList" size="10">
<f:selectItems value="#{listManyBean.selListUser}"/>
</h:selectManyListbox>
<h:commandButton id="clickGo" value="#{bundle.btn_login}"
type="submit"
action="#{listManyBean.submitList}"/>
<input type="button" value="Add" onclick="addUserToList();" />
</h:form>
Script to add to the list:
function addUserToList(){
var UserListBox = document.getElementById('UserList');
var UserNum = document.getElementById('UserNumber').value.toUpperCase();
var UserOption = new Option(UserNum,UserNum);
UserListBox.options[UserListBox.options.length] = UserOption;
}
Bean:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.model.SelectItem;
#ManagedBean
#RequestScoped
public class ListManyBean {
private List<String> listUser;
private List<SelectItem> selListUser;
public List<SelectItem> getSelListUser() {
return selListUser;
}
public List<String> getListUser() {
return listUser;
}
public void setListUser(List<String> listUser) {
this.listUser = listUser;
}
public void submitList() {
System.out.println("User List Value***" + this.listUser);
System.out.println("User ListPan***++"+selListUser);
}
}
I am getting null always, irrespective of adding one or more than one record.
Please let me know what is going wrong here.
You're adding new items using JS instead of using JSF. This way JSF won't know anything about the new items. This information is in no way been submitted to the server side.
Replace your wrong JS approach by a sane JSF approach:
<h:form>
<h:selectManyListbox value="#{bean.selectedUsers}" size="10">
<f:selectItems value="#{bean.availableUsers}" />
</h:selectManyListbox>
<h:commandButton value="submit" action="#{bean.submit}" />
<h:inputText value="#{bean.user}" />
<h:commandButton value="Add" action="#{bean.add}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
and
#ManagedBean
#ViewScoped
public class Bean {
private List<String> selectedUsers;
private List<String> availableUsers = new ArrayList<String>();
private String user;
public void add() {
availableUsers.add(user);
user = null;
}
public void submit() {
System.out.println("Selected users: " + selectedUsers);
System.out.println("Available users: " + availableUsers);
}
// ...
}
i have the following bean:
public class MyBean {
public ArrayList<ReportRow> getReportRows()
{
return reportRows;
}
private final ArrayList<ReportRow> reportRows =
new ArrayList<ReportRow>(Arrays.asList(
new ReportRow("","")
));
public ArrayList<ReportRow> getOrderList() {
return reportRows;
}
public String addAction() {
ReportRow row = new ReportRow("", "");
reportRows.add(row);
return null;
}
public class ReportRow{
String reportColumnName;
String reportColumnDesc;
public ReportRow(String reportColumnName,String reportColumnDesc) {
this.reportColumnName=reportColumnName;
this.reportColumnDesc=reportColumnDesc;
}
public String getReportColumnName()
{
return reportColumnName;
}
public void setReportColumnName(String reportColumnName)
{
this.reportColumnName = reportColumnName;
}
public String getReportColumnDesc()
{
return reportColumnDesc;
}
public void setReportColumnDesc(String reportColumnDesc)
{
this.reportColumnDesc = reportColumnDesc;
}
}
}
jsf page:
<t:dataTable value="#{myBean.reportRows}" var="o"
id="reportColumnsTable" styleClass="standardTable" headerClass="standardTable_Header"
rowStyleClass="#{myBean.viewDelayedRsd}"
>
<h:column>
<t:outputLabel value="Column name:"></t:outputLabel>
<t:inputText id="ReportColumnName" value="#{o.reportColumnName}" required="true">
</t:inputText>
</h:column>
<h:column>
<t:outputLabel value="Column Desc:"></t:outputLabel>
<t:inputText id="ReportColumnDesc" value="#{o.reportColumnDesc}" >
</t:inputText>
</h:column>
<h:column>
<h:outputLink value="#add"><h:outputText value="Add"/>
<a4j:support ajaxSingle="true" event="onclick" action="#{rprtBean.addAction}"
reRender="reportColumnsTable,msgPanel" />
</h:outputLink>
</h:column>
</t:dataTable>
problem is that when i click on add, it generates a new row, and clear the old one, and i want to maintain the values of old row, any ideas ?
You're using a <h:outputLink> instead of a <h:commandLink>. The <h:outputLink> doesn't submit the form at all, it fires a plain GET request. The <a4j:support> won't work properly inside a <h:outputLink>. Replace it by a <h:commandLink>:
<h:commandLink value="Add" action="#{rprtBean.addAction}">
<a4j:support reRender="reportColumnsTable,msgPanel" ajaxSingle="true" />
</h:commandLink>
Then, you need to ensure that you preserve the data model for subsequent request in case that your bean is request scoped. There are several ways to achieve this:
Set either Tomahawk datatable's preserveDataModel to true:
<t:dataTable preserveDataModel="true">
Or save the bean state in the view scope. Add the following tag somewhere in the page:
<t:saveState value="#{myBean}" />
or since you're also using RichFaces/Ajax4jsf:
<a4j:keepAlive beanName="myBean" />
i just used the a4j command link and everything worked fine.