I am trying to make a filter using selectOneMenu.
I have two categories, when one is selectect, must filter the results shown, and also the second category.
JSF code:
<div id="box-categories" class="box-left">
<b>Filter by topic</b>
<h:selectOneMenu id="cat1" binding="#{interfaceContainer.documentFormContainer.selectOnes['cat1'].selectOne}" rendered="true" onchange="javascript:refreshResults(); return false;">
<f:selectItems value="#{interfaceContainer.documentFormContainer.selectOnes['cat1'].items}" />
</h:selectOneMenu>
<b>and subtopic</b>
<h:selectOneMenu id="cat2" binding="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].selectOne}" rendered="true" onchange="javascript:refreshResults(); return false;" value="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].value}">
<f:selectItems value="#{interfaceContainer.documentFormContainer.selectOnes['cat2'].items}" />
</h:selectOneMenu>
</div>
But I have problems when I try to get the values using this java code:
public String getStringValue(){
if ( this.selectOne ==null || this.getSelectOne().getValue()==null)
return "";
return this.getSelectOne().getValue().toString();
}
I realised that the problem is just with getValue(), because debugging, this.getSelectOne() is in the rigth value, but this.getSelectOne().getValue() is null.
Any idea??
Thanks in advance
UIInput#getValue() will return null when you attempt to access it during any phase before the Update Model Values phase. You're apparently accessing it at the "wrong" moment in the JSF lifecycle. Anyway, creating dependent dropdown menus in JSF without help of a shot of Ajax is terrible.
Long story short, here's how to do it: Populate child menu's (with complete and working code examples).
Related
I have a problem I can not solve, I have a selectOneListbox with a Value Chang Listener and submit onclick. It works perfectly but the problem I have noticed is that the Set and Get methods I have for other elements in my form runs after the method that captures the ValueChangeListener. And I can not use the right data from the elements in my form, how do I resolve this?
So i got in my selectOneListbox:
<h:selectOneListbox onclick="Submit();"
valueChangeListener="#{normalbesoksgrenController.setActiveFromAllList}"
size="20" value="#{normalbesoksgrenController.currentVardTillfalleID}">
<f:selectItems itemValue="#{item.vardTillfalle.id}" itemLabel="#
{normalbesoksgrenController.getDateAndTime(item.getVardTillfalle().getStartTid())}"
var="item" value="#{normalbesoksgrenController.besokList}" ></f:selectItems>
</h:selectOneListbox>
And i got my backbean:
public void setActiveFromAllList(ValueChangeEvent event)
{
int id = Integer.parseInt(event.getNewValue().toString());
Doing some stuff..
}
I think you might want to use the ajax event like this:
<h:selectOneListBox .....>
<f:ajax execute="#form" listener="#{normalbesoksgrenController.setActiveFromAllList}" event="change" reder=":whatEverYouWant" />
</h:selectOneListBox>
The execute attribute defines what should be submitted before the ajax request is handled.
I need advise with selection listeners in p:dataTable. My view is primefaces extension layout
(pe:layout), with north, left and center section. North section is table and left is a menu.
The idea is that left menu provides a different view for the data in selected table row
and therefore, if the row changes, the whole view need to refresh. (Depending on the view selected in left menu - these are backed by beans backigOne, two and three and only one at the time is active).
So I decided to use multiple rowSelect events for the table, for every bean:
<p:dataTable id="" var="wo" value="#{TableBacking.dataList}"
selection="#{TableBacking.selectedItem}" selectionMode="single" rowKey="#{wo}">
<p:ajax event="rowSelect" listener="#{backingOne.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "ONE" />
<p:ajax event="rowSelect" listener="#{backingTwo.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "TWO"/>
<p:ajax event="rowSelect" listener="#{backingThree.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "THREE" />
...
</p:dataTable>
This works well and since always one item is selected in leftMenuBacking, only one ajax event will be enabled at the time.
The problem is, however, all the backingOne, backingTwo and backingThree beans gets always initialized, because of the declaration:
listener="#{backingXXX.tableChangeListnener}"
and in my case, initialization is costly :( (timewise)
I need a hint of better desing, so the functionality is the same, but only the backing bean of the menu which is curently selected (or enabled as in sense of disabled="#{leftMenuBacking.selection != "ONE") gets initialized and no other does?
Thanks a lot.
EDIT 1 based on Magnus Tengdahl comment:
There are different pages for every selection in leftmenu.
The page backingOne.xhtml looks something like this:
<ui:composition template="/publicResources/templates/gdfoxTemplate.xhtml">
<ui:define name="title">GDFox | Similar Problems</ui:define>
<!-- North contains the section with table that produces rowSelect event as described above -->
<ui:define name="north">
<ui:include src="currentWorkload.xhtml" />
</ui:define>
<!-- Contains the left munu, uses p:menu widget-->
<ui:define name="west">
<ui:include src="leftmenu.xhtml" />
</ui:define>
<!-- center view based on BackingOne bean-->
<ui:define name="center">
....
</ui:define>
</ui:composition>
So basically, every selection on left menu is on different URL (let's just call them backinOne/Two/Three.xhtml. They share all share north and west sections and defines unique center
This is why needed to use three for that table - in order to propage the change to all possible views (althought only one will be selected in time). I dont thing (== I am still failing to see) Magnus that one listenere would solve my problem. If you are sure your idea will work, could you please explain it little bit further?
I would go with having just one rowSelect listener, without any disabled conditions:
<p:ajax event="rowSelect" listener="#{backingOne.tableChangeListnener}"
update="menuArea" />
Then let the backing bean decide what should be done given the selected row. Have a look at the PrimeFaces ShowCase for an example on how to get the selected row in the backing bean. From that information the backing bean surely must know what to do. Basically, you could just call the appropriate backing bean implementation in one of the backing beans.
You haven't given us any code for the left view, but I would recommend something like (if you don't do already):
<h:panelGroup id="menuArea">
<ui:fragment rendered="#{leftMenuBacking.selection == 'ONE'}">
... code for selection "ONE" ...
</ui:fragment>
<ui:fragment rendered="#{leftMenuBacking.selection == 'TWO'}">
... code for selection "TWO" ...
</ui:fragment>
<ui:fragment rendered="#{leftMenuBacking.selection == 'THREE'}">
... code for selection "THREE" ...
</ui:fragment>
</h:panelGroup>
In this way, your left area will be re-rendered (i.e. updated) for every rowSelect and your selection table is left as it is.
I think you could make an extra bean backingbean0. In that bean you have the listener tableChangeListener. As Magnus stated you have 1 p:ajax
And in the tableChangeListener you can call backingbean1 2 or 3 depending on the one that is needed. (you have this info in your backingbean0)
protected Object getBean(String name) {
FacesContext fcontext = FacesContext.getCurrentInstance();
ELResolver resolver = fcontext.getApplication().getELResolver();
Object bean = resolver.getValue(fcontext.getELContext(), null, name);
if (bean == null) {
getLog().warn("An object with name=" + name + " could not be resolved with ELResolver");
}
return bean;
}
and you call it like this
BackingBean1 bb1 = (BackingBean1) getBean("bb1");
in a brief word here is the problem
when i value change of the menu it execute the post-constructor again in backing bean then execute method fillAreas and i used view scope .
<p:selectOneMenu id="governate" value="#{add.selectedGovern}" style="height:26px; text-align: right; width: 303px;"
valueChangeListener="#{add.fillAreas}" rendered="#{languageBean.isDefaultLanguage==true}" immediate="true" >
<f:selectItem itemLabel="---#{prompts._select} ---" itemValue="0"/>
<f:selectItems value="#{add.governrateList}" var="govern" itemLabel="#{govern.governrateName}" itemValue="#{govern.governrateId}" />
<f:ajax immediate="true"/>
</p:selectOneMenu>
what can i do to prevent calling post-constructor ? and if post-constructor called once why it called every time i select from menu ?
Thanks in advance .
A view scoped bean will be recreated on every single request when a property of it is been bound to an attribute of a taghandler (JSTL <c:forEach>, Facelets <ui:include>, JSF <f:validateXXX>, etc) or to the binding or id attribute of a JSF UI component (<h:someComponent>, etc).
This is related to JSF issue 1492. You could solve it by disabling the partial state saving for the specific view, or by looking for alternate ways to achieve the desired functional requirement.
See also:
Communication in JSF 2.0 - #ViewScoped fails in taghandlers
I have an ArrayList of objects and I use them as follow:
<ui:repeat value="#{BookReview.books}" var="book" >
<li>
<h:commandLink value="#{book.bookName}" action="detail" />
</li>
</ui:repeat>
in the detail page I show the book's comments, and I have a form to register a new comment:
<h:form>
Name:<h:inputText value="#{Comment.author}" />
Rate:<h:inputText value="#{Comment.rate}" />
Text:<h:inputText value="#{Comment.comment}" />
<h:commandButton action="#{book.addComment(Comment)}" value="Add Comment" />
</h:form>
My problem is that book isn't preserved until the next Request and #{book.addComment(Comment)} results in Target Unreachable, identifier 'book' resolved to null.
I have tried annotate the book as RequestScoped, didn't work, then I've modified to ViewScoped, didn't work either, then I tried to use a <inputHidden > to keep the object around, but it just uses a .toString() and I can't reuse the object.
I don't want to use session to store the object because I need it only once, and I don't think I want to use a converter because Book has a ArrayList of comments (also I think it is to cumbersome and complicated)
Put your BookReview bean to the session scope (or, if you're on JSF-2.0 - then let it have the view scope).
You've got to keep a handle of the current book somewhere and relate the new comment with it.
Create a new bean, BookDetail.
#ManagedBean
#ViewScoped
public class BookDetail {
private Book book;
private Comment comment = new Comment();
public String addComment() {
book.getComments().add(comment);
// You need to persist book here if necessary.
return "list";
}
// Add/generate getters/setters the usual way.
}
Set the selected book as follows (could be done nicer if you were using an UIData component like h:dataTable or t:dataList instead of ui:repeat):
<h:commandLink value="#{book.name}" action="detail">
<f:setPropertyActionListener target="#{bookDetail.book}" value="#{book}" />
</h:commandLink>
Rewrite the detail form as follows:
<h:form>
Name:<h:inputText value="#{bookDetail.comment.author}" />
Rate:<h:inputText value="#{bookDetail.comment.rate}" />
Text:<h:inputText value="#{bookDetail.comment.comment}" />
<h:commandButton action="#{bookDetail.addComment}" value="Add Comment" />
</h:form>
This question already has an answer here:
How to disable/enable JSF input field in JavaScript?
(1 answer)
Closed 3 years ago.
I'm developing a Java EE application (JSF2 + richfaces 3.3.3 + facelets).
I want to disable my h:selectOneMenu when loading my page, and when it finishes loading (using the function onload()), I want to re-enable my component.
I have something like this:
<ui:define name="infosHead">
<script type="text/javascript">
window.onload = function() {
document.getElementById("forme1_myform:valueCh").disabled = false;
alert("here");
}
</script>
</ui:define>
<ui:define name="infosBody">
<h:form id="forme1_myform" target="_blank">
<h:selectOneMenu id="valueCh" value="#{mybean.value}" disabled="true" >
<f:selectItems value="#{mybean.values}" />
<a4j:support event="onchange"
ajaxSingle="true"
limitToList="true"
reRender="id1,id2,...."
ignoreDupResponses="true"
action="#{mybean.actionme}"
oncomplete="getId();"/>
</h:selectOneMenu>
</h:form>
</ui:define>
this is working fine.
But my bean is getting nothing (mybean.value == null).
It's like he thinks that the component is still disabled.
how can I make this works ?
The problem is that you are enabling your component only on the client side. On the server side it will always be disabled="true". To make this work you must :
a. Assign the disabled property of your component to a managed bean property that will be initially 'true'
disabled="#{myController.valueChDisableStatus}"
b. Inside your h:form insert window.onload = callScript
c. Finally, in the myController#someAction method set the valueChDisableStatus property to false
I cant check the solution right now, but I believe it will work fine.
I found this solution.
<ui:define name="infosHead">
<script type="text/javascript">
window.onload = function() {
updateName(false); // sets 'disabled' from true to false
}
</script>
</ui:define>
<ui:define name="infosBody">
<h:form id="forme1_myform" target="_blank">
<h:selectOneMenu id="valueCh" value="#{mybean.value}" disabled="#{mybean.render}" >
<f:selectItems value="#{mybean.values}" />
<a4j:support event="onchange"
ajaxSingle="true"
limitToList="true"
reRender="id1,id2,...."
ignoreDupResponses="true"
action="#{mybean.actionme}"
oncomplete="getId();"/>
</h:selectOneMenu>
</h:form>
<a4j:form>
<!-- this is where it's going to reRender my component -->
<a4j:jsFunction name="updateName" reRender="valueCh">
<a4j:actionparam name="param1" assignTo="#{mybean.render}" />
</a4j:jsFunction>
</a4j:form>
</ui:define>
and this is the content of mybean:
public class MyBean implements Serializable {
private List<SelectItem> values;
private String value;
private Boolean render = true; // the page loads with element disabled
public void actionme(){...}
//getters & setters
}
Neither of these solutions worked for me.
While setting the element's disabled attribute from a managed bean value worked fine, and changing it's value via javascript also worked fine, once the form is submitted the "someaction" method is still not reached in order to "set the valueChDisableStatus property to false". In addition I found that even though my managed bean had an isDisabled() and a setDisabled(boolean value), the setDisabled() method was never called after submitting the form (of course), though the isDisabled() was. So I was unable to find a way using these solutions to change the managed beans "disabledElement" value to false.
I did find a solution that did work for me though at this link:
http://blog.michaelscepaniak.com/jsf-you-cant-submit-a-disabled-form-element
Basically it suggests that by default all the elements should be "enabled" from the JSF perspective, and that all enabling and disabling should be done via Javascript. It does point out the the client and server states are out of sync temporarily in this solution... but it works very well for my scenario regardless of the temporary mismatch.