JSF Form From Entity and Foreign Key Issue [duplicate] - jsf

This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 7 years ago.
Recently I did [CRUD Enterprise Application in NetBeans][1.] I made my own scenario for it namely storing scores for player. I have tree tables player, game and playerGame table. Every thing works fine with player and game table (add, remove, edit) as in tutorial form youtube but, I have problem with linked table (playerGame). When I try generate JSF Form From Entity using netBeans Palette I am getting this code
<h:selectOneMenu id="fkGameId" value="#{controller.playerGame.fkGameId}" title="FkGameId" required="true" requiredMessage="The FkGameId field is required.">
<!-- TODO: update below reference to list of available items-->
<f:selectItems value="#{fixme}"/>
</h:selectOneMenu>
Also I have tried this
<h:selectOneMenu id="fkPlayerId" value="#{controller.player.playerId}" title="FkPlayerId" required="true" requiredMessage="The FkPlayerId field is required.">
<!-- TODO: update below reference to list of available items-->
<f:selectItems value="#{controller.player.playerGameList}"/>
</h:selectOneMenu>
but with no result
in place where foreign keys to playerId and gameId should be inputed by palette.
My question is what I have to do to fix this, it would be nice to see similar example on linked tables but I didn't found anything (only one simple table examples I have found) I am newbie in JavaEE and this was my first tutorial ever in this subject and to be honest I don't know how to name thing properly.
Also trying to find the solution for the problem I did JavaServer Faces tutorial form netbeans website Generating JSF CRUD Application form Databases. The tutorial was pretty straight forward and I had no problem with it and it works fine with the same scenario (I was able to select foreign keys form dropdown list and create playerGame record). I have tried solve this problem based on JSF pages form this tutorial but the pages are generated using netBeans command JSF Pages form Entity Classes I because I have no experience in Java EE like mentioned before I have failed to solve the problem.
P.S. I you need me to provide more information please just ask.
UPDATE:
It is partially working now thanks to Geinmachi
Partial SOLUTION:
In my controller class I have added
private String playerList;
public String getPlayerList() {
return playerList;
}
public void setPlayerList(String playerList) {
this.playerList = playerList;
}
private List<Player> playerLists;
public List<Player> getPlayerLists() {
return playerLists;
}
public void setPlayerLists(List<Player> playerLists) {
this.playerLists = playerLists;
}
#PostConstruct
public void init(){
playerLists = playerFacade.findAll();
// playerLists = new ArrayList<>();
// playerLists.add( new Player(player.getPlayerId()));
}
public void submit(){
System.out.println("Selected Player: " + playerList);
}
and my jsf code looks like
<h:selectOneMenu value="#{controller.playerList}">
<f:selectItem itemValue="#{null}" itemLabel="#{player.playerName}"/>
<f:selectItems value="#{controller.playerLists}" var="player" itemValue="#{player.playerId}" itemLabel="#{player.playerName}"/>
</h:selectOneMenu>
the was found in one of links given by Geinmachi.
However now I am getting javax.ejb.EJBException: Transaction aborted
when trying to insert data to database because partial solution doesn't get fk_game_id.

Given fields in PlayerGame entity (with getters/setters)
private Player fkPlayerId
private Game fkGameId
In controller:
private List<Player> playerList
private List<Game> gameList
form:
<h:form>
<h:outputText value="Choose player"/>
<h:selectOneMenu value="#{controller.playerGame.fkPlayerId}" converter="playerConverter">
<f:selectItems value="#{controller.playerList}" var="player"
itemValue="#{player}" itemLabel="#{player.playerName}"/>
</h:selectOneMenu>
<h:outputText value="Choose Game"/>
<h:selectOneMenu value="#{controller.playerGame.fkGameId}" converter="gameConverter">
<f:selectItems value="#{controller.gameList}" var="game"
itemValue="#{game}" itemLabel="#{game.gameName}"/>
</h:selectOneMenu>
<h:commandButton action="#{controller.createPlayerGame}" value="Link player with a game"/>
</h:form>
In your controller you need lists of all players and all games to choose from. You have to create converters for entities because on the HTML page they are just String and JSF expects Player and Game objects. For POJO JSF converter you can search in google and read here
See:
h:selectOneMenu wiki page

Related

Use JSF form to create an object with a list of other objects

I am using JSF 2 with Glassfish 4. I would like to create an object that has a collection of objects as one of its fields. When searching, I can only find ways to display a collection field in a JSF form. Here I want the opposite: allow the user to populate this collection while creating the parent object. Simplified example below:
Parent Object: Account
public class Account {
private String accountName;
private List<Order> orderList = new ArrayList<Order>();
public String save() {
System.out.println(accountName);
System.out.println(orderList);
return "";
}
// Constructors, getters and setters below.
}
Child Object: Order
public class Order {
private String orderName;
private Integer orderCost;
// Constructors, getters and setters below.
}
JSF Page Body
The idea for the form was taken from BalusC's answer here.
<h:body>
<h1>Create Account</h1>
<h:form>
<h:panelGrid>
Account Name:
<h:inputText value="#{account.accountName}" />
<ui:repeat value="#{account.orderList}" varStatus="loop">
Order Name:
<h:inputText value="#{account.orderList[loop.index]}" />
Order Cost:
<h:inputText value="#{account.orderList[loop.index]}" />
</ui:repeat>
</h:panelGrid>
<h:commandButton action="#{account.save}" value="Create" />
</h:form>
</h:body>
I run into a few problems:
It's impossible for me to have a set number of Orders displayed. (ex: max 5 per new account). An input field is only displayed if the List already has some objects. This makes sense, but I would like to present the user with X blank lines they can fill in.
I am unable to expose both the orderName and orderCost fields at once to the user.
Later on I would like to add a commandButton that adds another row of inputText fields in the UI so the user can add however many orders to an account as they want.
Any help greatly appreciated. Happy to answer questions for anything I missed. Thank you!
After BalusC's help I made the following changes and I now have the behaviour that I want:
// Prop up the array so the desired number of fields appears in the UI
#PostConstruct
public void prepare() {
orderList.add(new Order());
orderList.add(new Order());
orderList.add(new Order());
}
Iterate through the list of empty Order objects. No data is disabled since all field values in the Order objects are null. Also, since I created the objects in #PostConstruct, the user's changes are easily saved on Submit.
<ui:repeat value="#{account.orderList}" var="order">
Order Name:
<h:inputText value="#{order.orderName}" />
Order Cost:
<h:inputText value="#{order.orderCost}" /><br/>
</ui:repeat>
As to preparing a fixed amount of items and adding a new item, just add a new item to the list.
orders.add(new Order());
Do this in #PostConstruct to prepare the items on page load and do the same in "Add" button.
As to accessing properties, you don't need the varStatus/index trick as you've there a collection of mutable objects, not a collection of immutable objects (where the question you found was all about).
<ui:repeat value="#{bean.orders}" var="order">
<h:inputText value="#{order.name}" />
<h:inputText value="#{order.cost}" />
</ui:repeat>
If you really insisted to, you could have done #{bean.orders[loop.index].name}, but as said, this is unnecessary.

Primefaces won't call setter on ManagedBean

I'm in the middle of building a web application (Spring 4, Primefaces 5.1 and JPA).
While one of my xhtml-pages has no problems working with its ManagedBean, the others won't really work. To be more specific, the UI input components (like inputText) won't call any setters from the managed Beans.
I've already run my Tomcat (8) on debug mode, which showed me that the page calls the get-methods, but no set-methods at all. If I try to persist something, all values are null (or 0, in case of an int-value). (it even persists an object into the database with all values null, though I have declared some #NotNull constraints which should be taken to the database configuration via JPA)
So, question is: How can I make my inputFields work with the fields of my ManagedBean? (Eclipse also shows me in the editor, that theoretically, the connection to the fields is there, it knows the managed bean, the field and the get-/set-methods)
SoftwareManagedBean.java
#ManagedBean(name = "swmb")
#ViewScoped
public class SoftwareManagedBean extends AssetManagedBean implements
Serializable {
private String bezeichnung;
private Software neueSoftware;
// +some more private fields, every single one with its get-/set-method
#Override
public String getBezeichnung() {
return super.getBezeichnung();
}
#Override
public void setBezeichnung(final String bezeichnung) {
super.setBezeichnung(bezeichnung);
}
//instantiante the field "neueSoftware"
public void createEmptySoftware(){
if(neueSoftware != null)
return;
this.neueSoftware = new Software();
}
//Persist Software with values from inputFields
public void addSoftware() {
createEmptySoftware();
neueSoftware.setBezeichnung(getBezeichnung());
softwareService.addSoftware(neueSoftware);
//...
neueSoftware = null;
}
viewSoftware.xhtml
<h:body>
<p:dialog header="Neue Software anlegen" widgetVar="SwNeuDialog" width="60%"
closeOnEscape="true" draggable="false" resizable="false" position="center">
<h:form id="SwDlgForm">
<h:panelGrid columns="3" border="0" >
<p:outputLabel for="swBezeichnung" value="Bezeichnung: " />
<p:inputText id="swBezeichnung" value="#{swmb.bezeichnung}"
label="Bezeichnung" required="true" />
<f:verbatim/>
<p:outputLabel for="swKategorie" value="Kategorie: " />
<p:selectOneMenu id="swKategorie" value="#{swmb.kategorie}" label="Kategorie" required="true" >
<f:selectItem itemLabel="Kategorie wählen" value="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{swmb.kategorieListe}" var="kat" itemLabel="#{kat.bezeichnung}" itemValue="#{kat}"/>
</p:selectOneMenu>
<p:commandButton value="neue Kategorie hinzufügen" />
<!-- + some more input fields -->
<p:commandButton value="Speichern" action="#{swmb.addSoftware()}" onclick="PF('SwNeuDialog').hide()" resetValues="true" process="#this"/>
<p:commandButton value="Abbrechen" onclick="PF('SwNeuDialog').hide()" resetValues="true" process="#this"/>
</h:panelGrid>
</h:form>
</p:dialog>
<!-- dataTable -->
</h:body>
AssetManagedBean.java
#ManagedBean
public abstract class AssetManagedBean {
//name of the hard-/software
private String bezeichnung;
//+ some more fields with get-/set methods
public String getBezeichnung() {
return bezeichnung;
}
public void setBezeichnung(String bezeichnung) {
this.bezeichnung = bezeichnung;
}
I hope that code is sufficient to see the problem, since the rest of the code follows the same structure. I think, the problem could lie within the xhtml file, but I don't see where or why. I've got the SpringBeanFacesELResolver (or however it is called), I've already looked through the code and compared it to another xhtml page and its Managed Bean, but there are no differences anymore. (though one is working, one not)
My debugger showed, how the working class/page (viewAdministration.xhtml) called the get-/set methods of the managed bean:
opening dialog window: get...(), set...()
clicking the commandButton to submit/persist: get() (old Value), set() (new Value), get() (new Value)
Another get() (called by the add... method)
(+ another get() for the dataTable on the main page)
on viewSoftware.xhtml, it looks like this:
opening dialog window: get()
clicking the commandButton to submit/persist:
another get() called by the addSoftware method
As you can see, when I try to submit, there is no set or get.
So, to summarize:
no setter called by trying to submit
the code on viewSoftware.xhtml and SoftwareManagedBean is similar to another, functioning ManagedBean + xhtml page (I've compared it again and again)
annotations in Managed Beans are the same (#ManagedBean, #ViewScoped)
the inputFields are inside a form (
I'm totally clueless, but I think it is some small mistake from my side that I can't just see.
I've searched through the web and especially stackoverflow, but all the problems and answers I've found couldn't help me finding what's wrong
Even without inheriting from a superclass it won't work (tried that out too)
I hope, you can help me. If this post is lacking some information, I'm sorry about that, I tried my best to not let this post grow too big and still get as much relevant information in it as possible.
So, I have found my mistake (or at least, I think I have). Only took me 2 weeks, but anyway...
I tried to test it out more specifically, wrote test classes and an xhtml page. Nothing worked (from simple Input over Dates to own classes).
The solution to this problem was to disable ajax on my commandButton (ajax="false"). When I tried to understand more of it, I realized that the commandButton opening the dialog window was nested in a facet inside a dataTable, and thus it had problems to properly set the values of the input fields.
So, thank you for your help. Maybe/hopefully this can or will help some other people later as well.
From the first glance at the code, without reading it whole, try putting process="SwDlgForm" on your command buttons, instead of process="#this". If that doesn't solve the problem, I'll read more carefully and try to help.

c:forEach + Data table multiple row selection crashes old selected values

i use JSF 2.0 and primefaces 4.0
my JSF code :
<c:forEach items="#{materielbean.materielist}" var="list" >
<p:dataTable var="car" value="#{materielbean.listeitemsmaterielbyidmateriel(list.idmateriel)}" rowKey="#{car.iditemsmateriel}"
selection="#{fournisseurbean.selectedItemsMateriel}" selectionMode="multiple" style="width : 664px; ">
<f:facet name="header">
#{list.nommateriel}
</f:facet>
<p:column headerText="designation">
#{car.designation}
</p:column>
<p:column headerText="Unité">
#{car.unite}
</p:column>
</p:dataTable>
</c:forEach>
and the used function
listeitemsmaterielbyidmateriel(list.idmateriel)
is defined like this
public List listeitemsmaterielbyidmateriel(int i){
return itemmaterielDAO.DisplayItemsMaterielDAOselonmMateriel(i);
}
And finally this is the DAO code
public List DisplayItemsMaterielDAOselonmMateriel(int idmateriel )
{
Query q = em.createQuery("select LIM from ItemsMateriel LIM inner join LIM.materiel where LIM.materiel.idmateriel= :idmateriel");
q.setParameter("idmateriel", idmateriel);
List l = new ArrayList();
l= q.getResultList();
return l ;
}
when i run this code , i got no errors , but selection="#fournisseurbean.selectedItemsMateriel}"
returns only the values of the final iteration(final datatable) , it's because in every iteration the list crashes old selected objects and put new selected objects , how can i do to prevent this ??
It's dangerous to mix JSTL core tags with JSF- and/or *Faces tags. Basically JSTL tag handler get executed during view build time, while JSF UIComponents get executed during view render time. See the very good answer at "JSTL in JSF2 Facelets… makes sense?"
Have you already tried to solve the issue using Facelets ui:repeat component?
Well sorry for late , but i discovored that the solution is easier than i thought :
First create a new list
List<ItemsMateriel> Tampon = new ArrayList<ItemsMateriel>();
Second modify the setter to :
public void setSelectedItemsMateriel(List<ItemsMateriel> selectedItemsMateriel) {
Tampon.addAll(selectedItemsMateriel);
this.selectedItemsMateriel = selectedItemsMateriel;
}
And finally to use the new list (Tampon) and you'll find all selected objects

PF's graphicImage doesn't render

I'am using JSF/PF anf I can't make a graphicImage work. Reviewing the tons of topics published on forums, this PF's graphicImage seems to be so tricky. I am obviously doing somethig wrong, but, as long as I am replicating code that worked for others (see post), it must be something in the environment of the component. I hope to find a solution here, i'm stuck for weeks. Thanks
Here is my original question in PF forum:
I encounter a problem rendering the image. I have followed the code explained and I correctly retrieve the id for image to display in a separate method:
public StreamedContent getStreamedImage() {
StreamedContent streamedImage = null;
UIViewRoot uiRoot = FacesContext.getCurrentInstance().getViewRoot();
System.out.println(uiRoot.getClientId());
UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent("itemDataForm:imagesTbl:itemImgComp");
Map attributes = component.getAttributes();
Integer image_id = (Integer)attributes.get("item_img_id");
if(image_id != null && editionItem != null && editionItem.getImages() != null){
for(ItemImageView img : editionItem.getImages()){
if(image_id.intValue() == img.getId()){
streamedImage = new DefaultStreamedContent(new ByteArrayInputStream(img.getImage()), "image/jpeg");
}
}
}else{
streamedImage = new DefaultStreamedContent(new ByteArrayInputStream(editionItem.getImages().get(0).getImage()), "image/jpeg");
}
.......
I could't manage to retrieve the (always null) so I tried with attribute and it works. So, the DefaultStreamContent is loaded, by the image doesn't render at all. My code for xhtml:
<p:dataTable id="imagesTbl" var="itemImg" value="#{itemEditionBean.editionItem.images}">
<p:column>
<h:panelGrid columns="1">
<h:outputText value="#{itemImg.id}"/>
<p:graphicImage id="itemImgComp" value="#{itemEditionBean.streamedImage}">
<f:attribute name="item_img_id" value="#{itemImg.id}"/>
</p:graphicImage>
</h:panelGrid>
</p:column>
</p:dataTable>
Exactly the same that the code working in this topic above. PS: I have mt dataTable enclosed within a tab. Maybe a dependency on the enclosing component, or form, or what?
There is a huge amount of code from other related topics that can be viewed in the link below:
http://forum.primefaces.org/viewtopic.php?f=3&t=4163&p=39751
Based on another page I found on building dynamic images, <f:param .../> should be used to supply a parameter to the getStreamedImage() method rather than <f:attribute .../>. Are you using a ConversationScoped backing bean? I was having the same problem displaying dynamic images, but found that there is a problem using them with ConversationScoped beans. I switched my backing bean to Session scope and now it works fine.

Duplicate Id. JSF

I have a problem with JSF. Can anyone say why this doesn't work?
<h:selectOneListbox
id="lang" size="5"
value="#{MbInstitution.node.lang}"
valueChangeListener="#{MbInstitution.changeLanguage}"
rendered="#{MbInstitution.view}"
>
<a4j:support event="onchange" reRender="shortDesc, fullDesc"/>
<f:selectItems value="#{MbInstitution.languagesByInstitute}"/>
</h:selectOneListbox>
<h:selectOneListbox
id="lang" size="5"
disabled="#{!MbInstitution.managingNew}"
value="#{MbInstitution.node.lang}"
rendered="#{!MbInstitution.view}"
>
<f:selectItems value="#{MbInstitution.availableLanguages}"/>
</h:selectOneListbox>
It says: "duplicate Id for a component instForm:lang"
I know that i have 2 elements with same Id, but one is rendered only when another isn't. So, i didn't think it would be a problem. Actually it's not a big problem at all as i don't need this id, but what if i needed then what would i do?
Your problem is that these two components are part of the JSF Component tree for this page. And even if they cannot be displayed at the same time, they share the same ID, which is not allowed by JSF.
I see three solutions to solve your problem:
First solution: Define two differents ID
Second solution: You can, as explained by Wayne Young, use a NamingContainer, which will prefix their ID by the ID of the NamingContainer.
Third solution: Use only one <h:selectOneListbox/> and then make the difference in the Java code.
<h:selectOneListbox id="lang" size="5" disabled="#{!MbInstitution.managingNew}" value="#{MbInstitution.node.lang}" valueChangeListener="#{MbInstitution.changeLanguage}">
<a4j:support event="onchange" reRender="shortDesc, fullDesc" rendered="#{MbInstitution.view}"/>
<f:selectItems value="#{MbInstitution.languages}"/>
</h:selectOneListbox>
Java code:
public List<SelectItem> getLanguage() {
if (isView()) {
return getLanguagesByInstitute();
} else {
return getAvailableLanguages();
}
}
public void changeLanguage(ValueChangeEvent evt) {
if (!isView()) {
return;
}
...
}
You'll have to use a different ID or put it in another naming container.
The Javadoc for UIComponent.setId() says:
The specified identifier must be
unique among all the components
(including facets) that are
descendents of the nearest ancestor
UIComponent that is a NamingContainer,
or within the scope of the entire
component tree if there is no such
ancestor that is a NamingContainer.

Resources