how to pass value from inputtext in foreach loop JSF - jsf

I have concluded that the function cannot be called if I place the h:form within the foreach loop.
If I place the form outside and the button outside the foreach it will call the correct function. But how do I get desired result with one button for each row where i can pass the input text as a new value to the function?
Note that the getSeriesForPlayerIInfo works as it should
<c:forEach var="list" items="#{serviceSeries.getSeriesForPlayerInfo(club.name, player.stringID, aSerie, calendarBean)}">
<h:form>
<h:outputText value=" #{list[0] }" />
<h:outputText value=" #{list[1] }" />
<h:outputText value="#{serie.getSerieDateString(list[2]) }" />
<h:outputText value="#{list[3]}"/>
<h:outputText value=" #{list[4] }" />
<h:outputText value=" #{list[5] }" />
<h:outputText value=" #{list[6] }" />
<h:inputText value=" #{list[7] }" />
<h:outputText value=" #{list[8] }" />
<h:commandButton action="#{serviceSeries.PlayerSerie}" value="Uppdatera">
</h:commandButton>
</h:form>
</c:forEach>

In this construct, the <c:forEach> runs during view build time producing the JSF component tree. In effects, you end up with physically multiple <h:inputText> components in JSF component tree, each with the same binding:
<h:inputText ... binding="#{serieScore}" />
<h:inputText ... binding="#{serieScore}" />
<h:inputText ... binding="#{serieScore}" />
...
This is not right! You're binding physically different components to one and same bean property, hereby causing a messed up view state shared between all those components.
Get rid of binding altogether. It's the wrong tool for the job anyway. You should be using the value attribute the right way in order to get/set a value.
<h:inputText value="#{list[7]}" />
Supply if necessary a Converter if it's not a standard type like String, Number, Boolean, etc.
See also:
JSTL in JSF2 Facelets... makes sense?
What is component binding in JSF? When it is preferred to be used?

Related

How to render a JSF component only if at least two children are rendered (title + item)?

I have a:
<h:panelGroup />
<h:outputText value="title" />
<h:itemThatSometimesWillShow rendered="sometimes1" />
<h:itemThatSometimesWillShow rendered="sometimes2" />
<h:itemThatSometimesWillShow rendered="sometimes3" />
...many more
And I would like that, if none of the itemThatSometimesWillShow shows, the whole panel (the title, actually) does not show either.
I did try with composite component's #{cc.childCount} > 1, but I'm not inside a composite implementation, so looks like it will always return 0.
Any idea? (I'm searching for something with js or EL to use in rendered attribute of the parent panelGroup)
This is achievable with EL 3.0 stream API. My initial attempt was:
<h:panelGroup rendered="#{component.children.stream().filter(c -> c.rendered).count() gt 1}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>
However, that didn't work quite well. It unexpectedly ran into an infinite loop which ultimately ended with an OutOfMemoryError. It appears that #{component} EL variable still represents the previous component at the moment the rendered attribute is consulted. This is a bit of a chicken-egg issue: the #{component} for current component is only injected if its rendered attribute evaluates true.
Given that, I can see two more options: explicitly find the component by ID as below,
<h:panelGroup id="foo" rendered="#{component.findComponent('foo').children.stream().filter(c -> c.rendered).count() gt 1}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>
or let it print some CSS class which in turn does a display:none;.
<h:panelGroup styleClass="#{component.children.stream().filter(c -> c.rendered).count() gt 1 ? 'show' : 'hide'}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>
i would shortly go with this:
<h:panelGroup rendered="{bean.isSometimes()}"/>
<h:outputText value="title" />
<h:itemThatSometimesWillShow rended="{bean.isSometimes1()}" />
<h:itemThatSometimesWillShow rended="{bean.isSometimes2()}" />
<h:itemThatSometimesWillShow rended="{bean.isSometimes3()}" />
and in the bean:
public boolean isSometimes()
{
return isSometimes1() || isSometimes2() || isSometimes3();
}

Pass <p:selectOneListbox var="ch"> as argument of <h:commandLink action>

I'm facing problem with passing object to backing bean from actionListener in commandLink. What I have, is a bean MeasureBean and a xhtml file, that uses the bean.
In the xhtml I have:
<p:selectOneListbox var="ch">
<f:selectItems value="#{MeasureBean.checkpoints}" var="cp" itemValue="#{cp}" />
<p:column>
<h:outputText value="#{ch.name}" />
</p:column>
<p:column>
<h:commandLink actionListener="#{MeasureBean.onCheckpointRemoved(ch)}">
<h:graphicImage library="#{ctx.theme}" name="images/delete.gif" />
<f:ajax event="click" />
</h:commandLink>
</p:column>
</p:selectOneListbox>
In the bean I have method:
public void onCheckpointRemoved(Checkpoint viewCheckpoint) {
System.out.println(viewCheckpoint);
// TODO
}
The problem is, that regardless of whethert I use the tag <f:ajax> or not, the parameter viewCheckpoint of the method in bean is always null. I need to pass that parameter to the bean. It doesn't have to be the whole object, it is allowed to pass just the id of the checkpoint. What I also tried, was:
<h:commandLink actionListener="#{MeasureBean.onCheckpointRemoved(cp)}">
(cp instead of ch). But no difference.
Please help,
Mateusz
You forgot to set the value of <p:selectOneListBox>. Also, you'll have to create a converter.
You can check an example of converter in PrimeFaces Showcase
<p:selectOneListbox var="ch" value="#{MeasureBean.checkPointTest}" converter="checkPointConverter">
<f:selectItems value="#{MeasureBean.checkpoints}" var="cp" itemValue="#{cp}" />
<p:column>
<h:outputText value="#{ch.name}" />
</p:column>
<p:column>
<h:commandLink actionListener="#{MeasureBean.onCheckpointRemoved(ch)}">
<h:graphicImage library="#{ctx.theme}" name="images/delete.gif" />
<f:ajax event="click" />
</h:commandLink>
</p:column>
</p:selectOneListbox>
Checkpoint checkPointTest;
// getter/setter....
public void onCheckpointRemoved(Checkpoint viewCheckpoint) {
System.out.println(viewCheckpoint);
// TODO
}

how do I pass outputtext to other form

as simple as this. But the outputtext is not passed to another function or form. inputtext of course works but looks ugly.
What should I subsititute outputtext with?
<h:form>
<h:outputtext value="xx" />
<h:commandButton action="#{serviceTest.function() }" value="test"
</h:commandButton>
</h:form>
Real world example
<p:column id="average" sortBy="#{resultClub.stringAverage}">
<f:facet name="header">Snitt</f:facet>
<h:outputText id="testing" value="#{resultClub.stringAverage}" />
<h:inputHidden id="hiddenAvg" value="#{resultClub.stringAverage}" />
</p:column>
javax.faces.component.UpdateModelException: javax.el.PropertyNotFoundException: /hcp/showAverages.xhtml #96,74 value="#{resultClub.stringAverage}": Property 'stringAverage' not writable on type com.jk.hcp.ResultClub
javax.faces.component.UIInput.updateModel(UIInput.java:867)
javax.faces.component.UIInput.processUpdates(UIInput.java:749)
org.primefaces.component.api.UIData.process(UIData.java:328)
After you described the problem to me, I figure it out for you...
You can do this by using javascript
Outputtext:
<h:outputText id="text1" value="xx" />
Button:
<h:commandButton value="click me"
action="#{serviceTest.function()}" value="test"
onclick="submitFieldValue()" >
</h:commandButton>
XHTML:
This will set the myfield instance variable in your controller. It basically will generate a java script function at compile time which will be able to call the controller.
<a4j:jsFunction name="setTheValue">
<a4j:actionparam name="param" assignTo="#{serviceTest.myfield}"/>
</a4j:jsFunction>
JavaScript:
This will call setTheValue with the outputtext value
function submitFieldValue(){
var x = document.getElementById("text1").value;
setTheValue(x);
}
If you want to have the "xx" value submitted after clicking on the commandButton, you can either use hidden field for it
<h:inputHidden value="some text" />
or you can use
<h:inputText readonly="true" />
which will render the text in an input text that user cannot change (it may look like the outputText), but its value will be submitted after clicking the button.
What I understand is that you want to view some data in the outputtext after the button is pressed, right?
Please if I got it wrong, tell me to delete the answer!
Is this case you need to make the button renders the outputfield upon clicked:
Outputtext:
<h:outputText id="text1" value="#{serviceTest.text1Value}" />
Button:
<a4j:commandButton value="click me"
action="#{serviceTest.function() }" value="test"
render="text1" >
</a4j:commandButton>
As you can see I used a4j:commandButton which will enable me to render any element on the page by id upon click.

Dynamic navigation with parameter passing in JSF

I want to pass the "title" parameter in the following listing dynamicaly to another jsf Facelet, depending on the selection of the selectOneMenu. My first approach looks like this:
<h:form id="form">
<p:selectOneMenu value="#{exerciseEditorBean.selectedExerciseType}" >
<f:selectItem itemLabel="Multiple Choice Exercise" itemValue="MultipleChoiceExercise" />
<f:selectItem itemLabel="Vocabulary Test" itemValue="VocabularyTest" />
</p:selectOneMenu>
<h:outputText value="Enter Title of your Exercise: " />
<h:inputText id="title" value="#{exerciseEditorBean.exerciseTitle}" />
<h:commandButton value="Next" action="#{exerciseEditorBean.openEditor()}" />
</h:form>
The ExerciseEditorBean is ViewScoped.
The openEditor() function then decides by the selectedExerciseType attribute which Facelet to show next and returns something like "multipleChoiceEditor.xhtml".
How can I now pass the titel attribute to this Facelet?
I now use the f:ViewParam in the target servelet, which works well except, that "multipleChoiceEditor.xhtml?includeViewParams=true" does not work, but this is another issue. Thanks for the discussion!

multiple h:forms in ui:repeat

I'm trying to have multiple h:forms on a page which are rendered with a ui:repeat component. If I have only one generated h:form, everything works perfect. If I have multiple h:forms, only the latest h:form will work! (If I try to submit another form then the last, only null is passed trough my service!)
<ui:repeat var="element" value="#{myService.elementList}">
<rich:simpleTogglePanel switchType="client"
label="#{element.codeElement} - #{element.description}"
opened="#{myService.isUiSelected(element)}"
onexpand="expand#{element.codeElement}()"
oncollapse="collapse#{element.codeElement}()">
<h:form id="newKindForm">
<a:commandLink ajaxSingle="true" id="idLink" onclick="#{rich:component('newTargetPanel')}.show()">
<a:commandButton id="myButton"
value="new Form"
action="#{myService.newForm(element)}"/>
</a:commandLink>
</h:form>
<rich:modalPanel id="newTargetPanel" autosized="true" width="450">
<f:facet name="header">
<h:outputText value="My Pannel Title" />
</f:facet>
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="/img/close.png"
id="hidelink"
styleClass="hidelink" />
<rich:componentControl for="newTargetPanel"
attachTo="hidelink"
operation="hide"
event="onclick" />
</h:panelGroup>
</f:facet>
<!-- THIS IS THE PROBLEMATIC FORM -->
<h:form>
<a:include viewId="../myRepeatableForm.xhtml" />
</h:form>
</rich:modalPanel>
</ui:repeat>
Some suggestion?
Thank You
you can contain everything in a single form, and use execute attribute to submit only the elements you want. like this:
<h:form id="newKindForm" prependId="false">
<ui:repeat id="newKindRepeat" var="element"
value="#{myService.elementList}" varStatus="varStatus">
<h:panelGroup id="newKindPanel">
<a:commandButton id="myButton"
execute="newKindRepeat:#{varStatus.index}:newKindPanel"
onclick="#{rich:component('newTargetPanel')}.show()"
value="new Form"
action="#{myService.newForm(element)}"/>
</h:panelGroup>
</ui:repeat>
</h:form>
please notice prependId of h:form, id and varStatus of ui:repeat, execute of a:commandButton.
btw, supposing that a: stands for ajax4jsf, i wouldn't recommend using commandButton nested in commandLink.
Is #{myService.elementList} a List ? If so, I'm not sure if that will work. Try using javax.faces.model.DataModel instead. Be sure to read the documentation carefully. It works something like this:
public Datamodel getElements(){
if(elements == null)
elements = new ListDataModel(getElementList());
return elements;
}
public List<Element> getElementList(){
elementList = foo(); // load the elements in your List like you did before
return elementList;
}
in your view: <ui:repeat var="element" value="#{myService.elements}">
I'm not familiar with RichFaces, this is the only suggestion I can make.

Resources