How can I dynamically change managed bean of "value" attribute? For example, I have h:inputText and, depending on typed-in text, managed bean must be #{studentBean.login} or #{lecturerBean.login}. In a simplified form:
<h:inputText id="loginField" value="#{'nameofbean'.login}" />
I tried to embed another el-expression instead of 'nameofbean':
value="#{{userBean.specifyLogin()}.login}"
but it doesn't worked out.
Polymorphism should rather be done in the model, not in the view.
E.g.
<h:inputText value="#{person.login}" />
with
public interface Person {
public void login();
}
and
public class Student implements Person {
public void login() {
// ...
}
}
and
public class Lecturer implements Person {
public void login() {
// ...
}
}
and finally in the managed bean
private Person person;
public String login() {
if (isStudent) person = new Student(); // Rather use factory.
// ...
if (isLecturer) person = new Lecturer(); // Rather use factory.
// ...
person.login();
// ...
return "home";
}
Otherwise you have to change the view everytime when you add/remove a different type of Person. This is not right.
Another way:
<h:inputText id="loginField1" value="#{bean1.login}" rendered="someCondition1"/>
<h:inputText id="loginField2" value="#{bean2.login}" rendered="someCondition2"/>
Related
I have a Stripes form using an Action bean.
I can store the data without any problem out of the form, but I did not find out how to prepopulate the form's data.
I have simplified my example to show what's not working.
My code under #Before is without any effect: the data dont go into the form.
How should I manage this approach?
myform.jsp:
...
<stripes:form beanclass="UserActionBean">
...
<stripes:text name="user" />
<stripes:submit name="store" value="Save" />
...
</stripes:form>
...
ActionBean:
public class UserActionBean implements ActionBean {
private String user;
#Before
public void init() {
user = "myuser";
}
#DefaultHandler
public Resolution store() {
...
}
}
You will need public getters and setters for Stripes to be able to read the value.
Although usually I would use the #DefaultHandler for the get, and then create a new handler for the save e.g. #HandlesEvent(value = "save") public Resolution save () {...
This might be crude, but I used a getter like Scary Wombat said and initialized the variable in the ActionBean. Or you could set its value in your handler that does the initial page display.
#Validate(required = true, on = {
"proceed"
})
private String tumblrUrl= "xyz.tumblr.com";
...
public String getTumblrUrl() {
return this.tumblrUrl;
}
public void setTumblrUrl(final String tumblrUrl) {
this.tumblrUrl = tumblrUrl;
}
I have a problem with taking names of tUsers and print them on the screen. May be i dont call the method for getting names properly () because when i call the function listAgencies, it prints them correctly in the Eclipse console. Thanks for any advices!
In .xthml file, I have:
<h:panelGrid id="panel2" columns="2" cellpadding="5">
<c:forEach items="${agencyBean.listAgencies()}" var="inputBoxes">
<h:outputText value="${inputBoxes.gettUser().name}" />
<h:inputText />
</c:forEach>
</h:panelGrid>
My bean class:
#ManagedBean(name = "agencyBean")
#SessionScoped
public class AgencyBean {
private TAgency tEventType = new TAgency();
public void listAgencies() {
EntityManager em = HibernateUtil.getEntityManager();
// read the existing entries and write to console
Query q = em.createQuery("select u from TAgency u");
List<TAgency> agencyList = q.getResultList();
for (TAgency agency : agencyList) {
System.out.println("NAme: " + agency.gettUser().getName());
}
}
public TAgency gettEventType() {
return tEventType;
}
public void settEventType(TAgency tEventType) {
this.tEventType = tEventType;
}
}
TUser is another entity from where i want to get the name. I have getName() method which is public.
The problem is here:
<c:forEach items="${agencyBean.listAgencies()}" ... >
It should look for a getter method for listAgencies attribute, but instead it is a void method that will be executed and there's nothing to access to.
The best bet would be:
Creating an attribute in your class called List<TAgency> listAgencies.
Define proper getter and setter methods for listAgencies attribute. NEVER define business logic in managed bean getters. Related: Why JSF calls getters multiple times
Probably, change the scope of the bean to #RequestScope to load this list every time users access to this view. Related: How to choose the right bean scope?
Load the list using #PostConstruct method.
Based on these advices, the code would look like this:
#ManagedBean(name = "agencyBean")
#RequestScoped
public class AgencyBean {
private TAgency tEventType = new TAgency();
private List<TAgency> listAgencies;
#PostConstruct
public void init() {
EntityManager em = HibernateUtil.getEntityManager();
// read the existing entries and write to console
Query q = em.createQuery("select u from TAgency u");
List<TAgency> agencyList = q.getResultList();
for (TAgency agency : agencyList) {
System.out.println("NAme: " + agency.gettUser().getName());
}
}
public TAgency gettEventType() {
return tEventType;
}
public void settEventType(TAgency tEventType) {
this.tEventType = tEventType;
}
public List<TAgency> getListAgencies() {
return listAgencies;
}
public void setListAgencies(List<TAgency> listAgencies) {
this.listAgencies = listAgencies;
}
}
And your JSF code:
<!-- Note: no parenthesis usage -->
<c:forEach items="#{agencyBean.listAgencies}" var="inputBoxes">
<!-- no need to call the getter verbosely, Expression Language call it for you automatically -->
<h:outputText value="#{inputBoxes.user.name}" />
<!-- what you want to do here? -->
<h:inputText />
</c:forEach>
Also, probably you don't want to use <c:forEach> but <ui:repeat> instead. Related: JSTL in JSF2 Facelets... makes sense?
I am setting a value in the login-bean when the user logs-in
using
--Login-bean
setMailNickname(mailnickname);
And in the info page I am able to retrieve the same value using
--InfoPage
<h:inputText value="#{login.mailNickname}" />
Now on the info page I am taking some more info from the user and saving all of them in the database, As one of the value is from the login form bean it is prepopulating on the Info-page but how to assign the same value to the info-page bean variable-
InfoBean.mailNickname
so that it can be saved into the database with the other fields which the user provides.
How can I assign the value to the infopage bean variable?
You can inject LoginBean into InfoBean, so that you can have a reference to its fields. As I understand one of your beans is at least #SessionScoped. You didn't provide that information, so I'd go as far as to guess that LoginBean is used for logging into your application or something like that and InfoBean to hold that information for future reference. Following that chain of thinking your InfoBean would look like that:
#ManagedBean
#SessionScoped
public class InfoBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
// other fields, methods...
}
and your LoginBean then would hold reference to session-scoped InfoBean:
#ManagedBean
#ViewScoped
public class LoginBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
#ManagedProperty("#{infoBean}")
private InfoBean infoBean;
public void setInfoBean(final InfoBean infoBean) {
this.infoBean = infoBean;
}
/** Method you use for populating */
public void populateInput(final String mailNicknameFromDb) {
setMailNickname(mailNicknameFromDb);
infoBean.setMailNickname(mailNicknameFromDb);
}
}
Remember about getters and setters for those fields as well as setter for managedProperty and be careful about scopes (you can't for example inject request-scoped bean into application-scoped bean, because the request-scoped one would probably not exist yet when creating application-scoped one).
I am learning JSF/EJB and I have run into a problem.
I am trying to write a code that takes a string from user and store that string to database.
Here's my code:
Entity bean:
#Entity
public class TestTable implements Serializable {
private static final long serialVersionUID = 1L;
public TestTable() {
super();
}
#Id
#GeneratedValue
private int firstcolumn;
private String secondcolumn;
private String testphrase = "test phrase";
public String getTestphrase() {
return testphrase;
}
public void setTestphrase(String testphrase) {
this.testphrase = testphrase;
}
public int getFirstcolumn() {
return firstcolumn;
}
public void setFirstcolumn(int firstcolumn) {
this.firstcolumn = firstcolumn;
}
public String getSecondcolumn() {
return secondcolumn;
}
public void setSecondcolumn(String secondcolumn) {
this.secondcolumn = secondcolumn;
}
}
Table has three columns, first column is primary key, second column stores string entered by user and third column stores "test phrase".
Controller bean:
#Named
public class TestController implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
DataAccess dacc;
#Inject
TestTable testTable;
public TestController()
{
}
public TestTable getTestTable() {
return testTable;
}
public void setTestTable(TestTable testTable) {
this.testTable = testTable;
}
public void test()
{
System.out.println("string secondcolumn= "+ testTable.getSecondcolumn());
dacc.addtodb(testTable);
}
}
I used System.out.println("string secondcolumn= "+ testTable.getSecondcolumn()); in method test() to check data before it is written to database. My problem is, it is always null. Output in console :
INFO :string secondcolumn= null .
secondcolumn is not set by value binding expression in JSF.
Now, JSF:
<h:outputText value="Second column:">
</h:outputText>
<h:inputText label="Second column" value="#{testController.testTable.secondcolumn}">
</h:inputText>
<h:outputText value="#{testController.testTable.getTestphrase()}">
</h:outputText>
<h:commandButton action="#{testController.test}" value="Save">
</h:commandButton>
I checked database and rows are being added. Entries in Column SECONDCOLUMN are NULL.
Entries in TESTPHRASE are "test phrase". I get no error messages and I have tried everything I can to solve the problem and now I am stuck. Any feedback are welcome.
Your problem is that you're injecting an entity class. The best will be initializing it manually using the new keyword, retrieving the entity from database, etc. One way to do this would be using a #PostConstruct method in your CDI bean:
#Named
//here you should define the scope of your bean
//probably #RequestScoped
//if you're working with JSF 2.2 there's already a #ViewScoped
public class TestController implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
DataAccess dacc;
//this musn't be injected since it's not a business class but an entity class
//#Inject
TestTable testTable;
public TestController() {
}
#PostConstruct
public void init() {
//basic initialization
testTable = new TestTable();
}
//rest of your code...
}
With this change, JSF will be able to set the values from the <h:form> into the bounded fields. Note that JSF code will just invoke the necessary getters and setters accordingly to the defined in your EL, it won't create a new instance of the bounded fields. The getters are invoked when generating the view and the setters when submitting the form to the server.
More info:
Creating new entities while enabling injection
Why use #PostConstruct?
StackOverflow Expression Language wiki
When or where do entities get created?
Do they get created when the XHTML page loads and accesses the entities via the managed bean?
Or do they get automatically created in the managed bean?
Do we need to manually create it from the managed bean's constructor?
Please see the code below (some necessary code might not have been copied.)
The entity would be:
public class PersonalInfo implements Serializable {
#Size(max = 50)
#Column(name = "FIRST_NAME", length = 50)
private String firstName;
// some getters and setters
}
the web page would be:
<h:form>
<h:outputText value="first name"/>
<h:inputText value="#{personalInforController.personalInfo.firstName}" />
<h:commandButton value="hit me"
action="#{personalInforController.create}"
immediate="true"/>
</h:form>
and the backing bean would be:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
}
In the example code given, the create action indeed doesn't seem to be able to work. The entity must be created by the backing bean before that.
If it's a simple entity, either the constructor or an #PostConstruct method would work. For instance:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
#PostConstruct
public void init() {
personalInfo = new PersonalInfo();
}
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
Some notes about the code. It's highly suspicious, and most likely plain wrong, to declare your bean to be #SessionScoped. If personalInfo is being edited in two tabs or windows you'll be in a world of hurt. I suggest making your bean #ViewScoped (for CDI, there's a separate extension made by the Seam3 that enables this, if you can't/won't use this extension consider using #ManagedBean instead of #Named).
Also, you might want to declare your instance variables to be private and give ejbFacade a better name (e.g. personalInfoFacade). I also doubt whether immediate is necessary on the commandButton, and since the outputText is obviously a label for the given inputText, you might want to consider using outputLabel and the for attribute.