Binding dynamic generated components - jsf

Jdev version: 11.1.1.7
I created Data control from a Java bean. I bind a jspx page with the data control attributes.
In that page I created components dynamically (forEach loop).
The issue is components only created(incremented) but the binding values is not different.
Code:
Bean:
public class ProposalBean
{
private String name;
private String age;
public ProposalBean()
{
super();
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(String age)
{
this.age = age;
}
public String getAge()
{
return age;
}
}
JSPX:
<af:form id="f1">
<af:panelGroupLayout id="pgl1">
<af:panelTabbed id="pt1">
<af:forEach var="var" varStatus="vs" begin="1" end="3">
<af:showDetailItem text="Tab #{vs.index}" id="sdi1">
<af:inputText value="#{bindings.name.inputValue}"
label="#{bindings.name.hints.label}"
required="#{bindings.name.hints.mandatory}"
columns="#{bindings.name.hints.displayWidth}"
maximumLength="#{bindings.name.hints.precision}"
shortDesc="#{bindings.name.hints.tooltip}"
id="it1">
<f:validator binding="#{bindings.name.validator}"/>
</af:inputText>
<af:inputText value="#{bindings.age.inputValue}"
label="#{bindings.age.hints.label}"
required="#{bindings.age.hints.mandatory}"
columns="#{bindings.age.hints.displayWidth}"
maximumLength="#{bindings.age.hints.precision}"
shortDesc="#{bindings.age.hints.tooltip}"
id="it2">
<f:validator binding="#{bindings.age.validator}"/>
</af:inputText>
</af:showDetailItem>
</af:forEach>
</af:panelTabbed>
<af:commandButton text="submit" id="cb1" action="next"/>
</af:panelGroupLayout>
</af:form>
Note: In forEach loop end is dynamic.

Because bindings is a merely way to connect view to the model, no magic.
I assume that you have some datasource with iterator.
You have to use this datasource iterator in your foreach loop. And you can use model as datasource or your bean for some cases.
Check this samples:
forEach documentation
jdevotnharves blog

Related

JSF ui repeat : Array index out of range: 0 [duplicate]

I would like to know if it possible to push a value from inside a <ui:repeat> to a map, a set or a list?
I would like to pass the value of the <h:inputtext> to a set.
Code:
<ui:repeat var="_par" value="#{cmsFilterParameterHandler.normaleSuchParameter()}">
<p:outputLabel value="#{_par.bezeichnung}" />
<p:spacer width="5px" />
<p:inputText id="me" value="#{??? push me to a set ???}"/>
<br /><br />
</ui:repeat>
With a Set, it is not possible as it doesn't allow referencing items by index or key. It's however possible with a List and a Map by just specifying the list index and map key in the input value.
With a List:
private List<String> list; // +getter (no setter necessary)
#PostConstruct
public void init() {
list = createAndFillItSomehow();
}
<ui:repeat value="#{bean.list}" varStatus="loop">
<h:inputText value="#{bean.list[loop.index]}" />
</ui:repeat>
With a Map (only if your environment supports EL 2.2 or JBoss EL):
private Map<String, String> map; // +getter (no setter necessary)
#PostConstruct
public void init() {
map = createAndFillItSomehow();
}
<ui:repeat value="#{bean.map.entrySet().toArray()}" var="entry">
<h:inputText value="#{bean.map[entry.key]}" />
</ui:repeat>
Noted should be that the canonical approach is to use a List of fullworthy javabeans. Let's assume a Javabean class named Par with properties id and value which maps exactly to a par table in DB with columns id and value:
private List<Par> pars; // +getter (no setter necessary)
#PostConstruct
public void init() {
pars = createAndFillItSomehow();
}
<ui:repeat value="#{bean.pars}" var="par">
<h:inputText value="#{par.value}" />
</ui:repeat>
Either way, it works as good when using <p:inputText>, it's in no way related to PrimeFaces, it's in the context of this question merely a jQuery based JSF UI component library. Just replace h: by p: to turn it on.
I'm not sure, if I understood your requirements correctly.
I suppose the following: You need a List of Strings in some backend and an ui:repeat tag to iterate over those strings with input-fields to edit them. Maybe there are some syntax-issues, but my idea should be clear:
public class Backend {
private List<String> myStrings;
public MyStringWrapper getMyStringWrapper(int index) {
return new MyStringWrapper(index);
}
public class MyStringWrapper {
private final int index;
public MyStringWrapper(int index) { this.index = index; }
public String getContent() { return myStrings.get(index); }
public void setContent(String newContent) { myStrings.add(index, newContent); }
}
}
In the frontend you use as follows:
<ui:repeat var="_index" value="#{backend.getIndexSequence()}">
<p:inputText value="#{backend.getMyStringWrapper(_index).content}"/>
</ui:repeat>
Of course, you have to provide a getIndexSequence-method which produces a list of ints ranging from 0 to the size of the strings.
Do you mean like this?
<p:inputText id="me" value="#{_par.input}"/>
in BackBean:
public class Par implements Serializable {
private String inputText;
private String bezeichnung;
public Par()
{
}
public void setInput(String input)
{
this.inputText = input;
}
public String getInput()
{
return this.inputText
}
public void setBezeichnung(String bezeichnung)
{
this.bezeichnung = bezeichnung;
}
public String getBezeichnung()
{
return this.bezeichnung
}
}

Weird mark questions between Class members

I have a separate module project setup to load from jar(this is working as expected) but when I try to load a List of objects in datatable or h:selectOneMenu then Class member are shown instead values i.e
public class Client implements Serializable {
private BigInteger idclient;
private String name;
public BigInteger getIdclient() {
return this.idclient;
}
public void setIdclient(BigInteger idclient) {
this.idclient = idclient;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
in controller i have List listClient;
<h:selectOneMenu styleClass="select-input"
id="registerzoneClient"
valueChangeListener="#{managerZoneController.listCountries}"
onchange="this.form.submit();">
<f:selectItem itemLabel="Client" itemValue="-1" />
<f:selectItems value="#{managerZoneController.listClients}"
var="client" itemLabel="#{client.name}"
itemValue="#{client.idclient}" itemDescription="#{client.name}" />
</h:selectOneMenu>
selectOneMenu label is ???name??? and value is ???idclient???

Passing parameters in JSF and PrimeFaces

I am studying a PrimeFaces AutoComplete demo. I shortenied it from the full showcase demo. http://www.primefaces.org/showcase/ui/input/autoComplete.xhtml
AutoCompleteBean.java
#ManagedBean
public class AutoCompleteBean {
private Query query;
private List<Query> queries = new ArrayList<Query>();
#PostConstruct
public void init() {
queries.add(new Query(0, "Afterdark", "afterdark"));
queries.add(new Query(1, "Afternoon", "afternoon"));
queries.add(new Query(2, "Afterwork", "afterwork"));
queries.add(new Query(3, "Aristo", "aristo"));
}
public List<Query> completeQuery(String query) {
List<Query> filteredQueries = new ArrayList<Query>();
for (int i = 0; i < queries.size(); i++) {
Query skin = queries.get(i);
if(skin.getName().toLowerCase().contains(query)) {
filteredQueries.add(skin);
}
}
return filteredQueries;
}
public void onItemSelect(SelectEvent event) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Item Selected", event.getObject().toString()));
}
public Query getQuery() {
return query;
}
public void setQuery(Query query) {
this.query = query;
}
}
Query.java
public class Query {
private int id;
private String displayName;
private String name;
public Query() {}
public Query(int id, String displayName, String name) {
this.id = id;
this.displayName = displayName;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return name;
}
}
I omitted a Convert class, which I think is not that relevant.
search.xhtml
<h:form>
<p:growl id="msgs" showDetail="true" />
<h:panelGrid columns="2" cellpadding="5">
<p:autoComplete id="queryPojo" value="#{autoCompleteView.query}"
completeMethod="#{autoCompleteView.completeQuery}" var="query"
itemLabel="#{query.displayName}" itemValue="#{query}"
converter="queryConverter" forceSelection="true" />
<p:commandButton value="search" oncomplete="PF('dlg').show()"/>
</h:panelGrid>
</h:form>
I have three questions for this:
1) completeMethod="#{autoCompleteView.completeQuery}": completeQuery method is called without passing a parameter, but it's defined as completeQuery(String query). How does this work?
2) value="#{autoCompleteView.query}". Query is an object defined in AutoCompleteBean. How can this Query object take user input string as its value? Usually InputText's value is good for taking user's input, which is a String value.
3) Can I still add an attribute "action=..." to the p:autoComplete componenet?
The converter class that you omitted here plays the real game.... Lets see your questions
As you see converter class overrides 2 methods
getAsString and getAsObject
1)the value
completeMethod="#{autoCompleteView.completeQuery}
gets refactred to
autoCompleteView.completeQuery(autoCompleteView.query);
as you can find to string method in Query class.
2).as converter is defined for autocomplete it calls getAsString method to render on screen. when selected getAsObject method is called to convert string value to object(Query).
3)you can use ajax select event
<p:ajax event="select" listener="#{autoCompleteView.someMethod}">
or call a remoteCommand by onSelect attribute in p:autoComplete
<p:autoComplete id="queryPojo" value="#{autoCompleteView.query}" onSelect="someRemoteCommand();"
completeMethod="#{autoCompleteView.completeQuery}" var="query"
itemLabel="#{query.displayName}" itemValue="#{query}"
converter="queryConverter" forceSelection="true" />
<p:remoteCommand name="someRemoteCommand" update="queryPojo" actionListener="#{autoCompleteView.execute}" />

Custom component inside <ui:repeat> doesn't find iterated item during encode

I'm trying to create a custom component for displaying an Entity with a certain form. So I've created my #FacesComponent and he's working but only when he is not inside a loop like <ui:repeat>. When I'm using the following code, my component is displaying null values for price and photo but not for name. Do you have an explaination ?
XHTML code :
<ui:define name="content">
<f:view>
<h:form>
<ui:repeat value="#{dataManagedBean.listNewestCocktails}" var="item" varStatus="status">
<h:outputText value="#{item.price}"/> <!--working very well-->
<t:cocktailVignette idPrefix="newCocktails" name="foo" price="#{item.price}" urlPhoto="#{item.photoURI}"/> <!-- not working the getPrice here -->
</ui:repeat>
<!--<t:cocktailVignette idPrefix="allCocktails" name="OSEF" price="20" urlPhoto="osefdelurl" ></t:cocktailVignette> -->
</h:form>
</f:view>
My component code :
package component;
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.ResponseWriter;
#FacesComponent(value = "CocktailVignette")
public class CocktailVignette extends UIComponentBase {
private String idPrefix;
private String name;
private String price;
private String urlPhoto;
public String getIdPrefix() {
return idPrefix;
}
public void setIdPrefix(String idPrefix) {
this.idPrefix = idPrefix;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getUrlPhoto() {
return urlPhoto;
}
public void setUrlPhoto(String urlPhoto) {
this.urlPhoto = urlPhoto;
}
#Override
public String getFamily() {
return "CocktailVignette";
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.write("<div id=\""+idPrefix+name+"\" class=\"cocktail-vignette\">");
writer.write("<h2>"+name+"</h2>");
writer.write("<h3>"+price+"</h3>");
writer.write("</div>");
}
}
Thanks a lot :) I'm trying but nothing is working ...
All of component's attributes which are sensitive to changes in state (e.g. the value being dependent on <ui:repeat var>, at least those which is not known during view build time but during view render time only), must delegate the storage of attribute value to the state helper as available by inherited getStateHelper() method.
Kickoff example:
public String getPrice() {
return (String) getStateHelper().eval("price");
}
public void setPrice(String price) {
getStateHelper().put("price", price);
}
Apply the same for all other attributes and get rid of the instance variable declarations. Important note is that the state helper key ("price" in above example) must be exactly the same as attribute name.
See also:
How to save state when extending UIComponentBase

JSF UIRepeat and PostBack

I have a simple page where a I use <ui:repeat> and it gets the value from a backing bean.
The initial request will give it an empty list. The postback then will invoke an action that will change the model behind the <ui:repeat> but it is not rendered?!
I debugged through it and I saw that the <ui:repeat> evaluates the value at restore view phase but thats it. When it reaches render response it does not use the latest value from my bean. Is that the expected behavior?
How can I make that work? Do I have to write my own repeat tag?
I can't really tell what could be the problem without some of your code, but these are the basics:
Backing bean:
public class ObjectService{
private DataModel objectDataModel;
private List<Object> objectList;
private Pagination paginationHelper;
private ObjectDao objectDao = new ObjectDao();
private String queryOption;
public void setQueryOption(String queryOption){
this.queryOption = queryOption;
}
public String getQueryOption(){
return this.queryOption;
}
public <E> PaginationHelper getPagination(final List<E> list) {
pagination = new PaginationHelper(10) {
#Override
public int getItemsCount() {
return list.size();
}
#Override
public DataModel createPageDataModel() {
return new ListDataModel(list);
}
};
return pagination;
}
public void setPagination(PaginationHelper pagination) {
this.pagination = pagination;
}
public List<Object> getObjectList(){
this.objectList = objectDao.readObjectsWhere(queryOption);
return this.objectList;
}
public void setObjectList(List<Object> objectList){
this.objectList = objectList;
}
public DataModel getObjectDataModel(){
if (objectDataModel == null) {
objectDataModel = getPagination(getObjectList()).createPageDataModel();
}
return objectDataModel;
}
public void setObjectDataModel(DataModel objectDataModel){
this.objectDataModel = objectDataModel
}
public String changeModel(){
objectDataModel = null;
return null;
}
}
XHTML page:
...
<h:form>
<fieldset>
<label>
<span>Option:</span>
<h:inputText value="#{objectService.queryOption}" />
</label>
<h:commandButton action="#{objectService.changeModel}" value="request data" />
</fieldset>
<ui:repeat value="#{objectService.objectDataModel}" var="objectVar">
<h:outputLabel value="#{objectVar.property1}" />
<h:outputLabel value="#{objectVar.property2}" />
<h:outputLabel value="#{objectVar.property3}" />
</ui:repeat>
</h:form>
...

Resources