Duplicate Id. JSF - 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.

Related

JSF Form From Entity and Foreign Key Issue [duplicate]

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

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.

Richfaces valueChangeEvent on input not working

I'm trying to use an richfaces inputNumberSlider or inputNumberSpinner.
The problem is I'm not able to update the values in my beans.
Here are the 2 solutions I tried:
1)
<rich:inputNumberSlider value="#{skinningBean.currentSkin.topBar.bannerXOffset}"
valueChangeListener="#{skinningBean.valueBannerXOffSetChangeListener}"
onchange="A4J.findForm(this).submit()">
</rich:inputNumberSlider>
In the bean:
public void valueBannerXOffSetChangeListener(ValueChangeEvent event) {
System.out.println("x value changed");
currentSkin.getTopBar().setBannerXOffset((Integer) event.getNewValue());
}
2)
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="change" render="preview" oncomplete="initSlider()" />
</rich:inputNumberSpinner>
This should just call my setter in the bean. I havw written two setter one which takes a String and one which takes an Integer. None of them is called
Although I need an a4j supprt anyway to rerender my items, a working solution for number 2 would be preferred
Try the following first, once you get it working you can add the oncomplete part:
<rich:inputNumberSpinner value="#{skinningBean.currentSkin.topBar.bannerYOffset}">
<a4j:ajax event="onchange" render="preview" action="#{bean.valueBannerXOffSetChangeListener}" />
</rich:inputNumberSpinner>
Possible you will need to redefine your bean function to not receive parameters.
Reference:
https://community.jboss.org/message/588944#588944

Find one or more components within f:facet - does it work as designed?

I have on my page a custom component with a Facet inside
<jtcomp:blockUI ...>
<f:facet name="events">
<f:param name="filtering" value="true"/>
<f:param name="sorting" value="true"/>
<f:param name="paging" value="true"/>
</f:facet>
...
</jtcomp:blockUI>
In the renderer class I intend to gather all UIParameter (f:param). At first I get the facet as follows
UIComponent facet = blockUI.getFacet("events");
Well. Now I thought I can call facet.getChildren() and iterate then over all childs. But I have debugged and figured out I can only do it if f:facet contains more than one f:param components. If it only has one f:param like this
<jtcomp:blockUI ...>
<f:facet name="events">
<f:param name="filtering" value="true"/>
</f:facet>
...
</jtcomp:blockUI>
the call above delivers already this component. I mean, facet is an UIParameter. Therefore, the entire logic looks like
// collect all f:param
List<UIParameter> uiParams = new ArrayList<UIParameter>();
if (facet instanceof UIParameter) {
// f:facet has one child and that's f:param
uiParams.add((UIParameter) facet);
} else if (facet != null && facet.getChildren() != null) {
// f:facet has no or more than one child
for (UIComponent kid : facet.getChildren()) {
if (kid instanceof UIParameter) {
uiParams.add((UIParameter) kid);
}
}
}
Is it an expected JSF behavior or just a Mojarra bug (I'm using Mojarra 2.1.0-b02)? I know, that before JSF2 only one component was allowed to be inside of f:facet. Maybe they still check it and don't instantiate FacetsMap if only one child component is available. Instead of FacetsMap containing all child components there is then the child component self bound as a facet to the parent component.
What do you think? I could nothing find in the JSF specification. Thanks in advance for your replies!
Ok, found the answer in the method addComponent from ComponentSupport. java
/**
* Add the child component to the parent. If the parent is a facet,
* check to see whether the facet is already defined. If it is, wrap the existing component
* in a panel group, if it's not already, then add the child to the panel group.
* If the facet does not yet exist, make the child the facet.
*/
public static void addComponent(FaceletContext ctx, UIComponent parent, UIComponent child)
All facets children are included into a UIPanel automatically, so that my code works fine.
I don't know where it is specified but I found a comment in the official Java EE tutorial.
From the Java EE 6 tutorial (including JavaServer Faces 2.0):
Facets can have only one child, so an
h:panelGroup tag is needed if you want
to group more than one component
within an f:facet
Maybe wrapping your params inside an h:panelGroup will help you.

Resources