Value not retained for action parameter when inside ui:repeat - jsf-2

Below is my Code:
<ui:repeat var="status" value="#{showUpdatedAction.statusUpdates}">
<h:panelGroup>
#{status.content}
<h:form>
<h:commandLink value="Like" action="#{statusAction.likeStatus(status.id,1)}" />
</h:form>
</h:panelGroup>
<ui:repeat>
#{status.content} shows correct values. When I print id of status using #{status.id}, it also gives correct value. But when I click the command link, value passed is always 0 for status.id.
Can someone tell me why this happens and how can I avoid this?
Thank you.
Edit 1
Interestingly, when instead of passing the parameter in function, I pass it using <f:param>, it works perfectly. Can anyone comment on that?

I think you should try using <c:forEach> instead of <ui:repeat>.

I can't tell you exactly, why status.id is 0 in your case but you can directly pass the whole status object in your EL expression. Like so:
<h:commandAction value="Like" action="#{statusAction.likeStatus(status)}" />
Then in your likeStatus you simply do a int statusId = status.getId() or similar and you have what you want.
As an addition: Using <c:forEach> should actually be just a fallback, because people say you shouldn't mix JSTL with JSF for whatsoever reasons.

Your code in the JSF page is just fine, just checked it... (generated the beans at my side too : showUpdatedAction, statusAction , and a simple class Status)
public void likeStatus(String id,long someVal){
System.out.println(id+"___"+someVal);
}
which prints the ids just fine
id1___1
id4___1
Maybe its something to do with the type of the id or something with your beans?

Related

ZK Binding NotifyChange not work on onChanging Event?

I currently use ZK for web-development. Here is my case:
I implement instant search, once text change=> perform search.
Zul File
<textbox id="textSearch" sclass="search_text">
<attribute name="onChanging">
lbOnChangingSearch.setValue(event.getValue());
vm.onChangingTextSearch();
</attribute>
</textbox>
<label id="lbOnChangingSearch" visible="false"></label>
<grid id="gridChapter" model="#load(vm.chapterInPage)">
....
</grid>
Controller code
ListModelList<ChapterJoinComic> chapterInPage;
public ListModelList<ChapterJoinComic> getChapterInPage() {
return chapterInPage;
}
#NotifyChange({ "topComics", "chapterInPage"} )
#Command
public void onChangingTextSearch() {
FilterObject fo = getFilterObject();
fo.setSearch_str(lbOnChangingSearch.getValue());
//
doSearch(fo); // Change chapterInPage
// Manually post Not
BindUtils.postNotifyChange(null,null,this.chapterInPage,"chapterInPage");
}
Problem
After call onChangingText search, Grid dont update databinding.
But if I continue change text (more call onChangingTextSearch ). The Grid will update, but the updated value is the previous value.
It seems the Grid is a-step slower than my latest Model object.
Note If I use onOK instead of onChanging event, the databinding works well.
Anyone can help me. Thanks in advance!
In addition of Malte his answer.
Textbox only sends data to the server with the onChange event to avoid needless network traffic.
If you want to send data to the server with the onChanging event, you need to do :
<textbox instant="true" />
In this case the client will update almost instantly to the server (if you type fast, it will be when you stop typing)
You should remove the BindUtils.postnotifyChange when you use #NotifyChange already, and you use it wrong anyway: the third parameter should be this instead of this.chapterInPage. The JavaDoc explains that you need to specify the bean whose property is changing and the name of the property.
Furthermore, replace your onChanging attribute with the proper way to call a command:
<textbox id="textSearch" sclass="search_text"
onChanging="#command('onChangingTextSearch')" />
Consult the documentation for more information on how to use commands. I think because you do not use the command as a command, the #NotifyChange is not triggered. And your postNotifyChange is wrong, as I said.
Let me know if that works or if there are other problems remaining.
EDIT
I just re-created an example on my own, and it seems to work. Try it like this:
ViewModel --------------------------------
private String searchText = "";
#NotifyChange({"chapterInPage", "searchText"})
#Command
public void onChangingTextSearch(#BindingParam("text") String searchText)
{
this.searchText = searchText;
}
public String getSearchText()
{
return searchText;
}
public ListModelList<String> getChapterInPage()
{
return new ListModelList<>(searchText.split(""));
}
zul --------------------------------------
<textbox onChanging="#command('onChangingTextSearch', text=event.value)" />
<label id="lbl" value="#load(model.searchText)" />
<listbox model="#load(model.chapterInPage)" />
Note that I use command binding to call the search method in the model instead of calling it "manually" in an onChanging listener. This way, I actually execute it as a command, which triggers the notifyChange. When you call it like vm.onChangingTextSearch() in a listener, the #NotifyChange is ignored.
This way, it works as expected, and with every character typed (well, after a couple of millisenconds delay), the list updates. Another advantage is that you do not have to bind your label into the view model, something that zk's documentation discourages.
Can you try to link your zul and model like this and tell me if it works. If it doesn't, you might want to try to create an example on zkFiddle that re-produces your code's behavior.

p:selectBooleanButton doesn't render preselected value

I been reading / trying examples for hours, and I can't make it work. I'm using Primefaces 4.0
I just need a way to select/unselect and assign those values to a Map
The xhtml looks like this.
<p:selectBooleanButton value="#{presupuestoBean.itemsCambiar[itemPresupuesto.id]}"
onLabel="Yes" offLabel="No" onIcon="ui-icon-check" offIcon="ui-icon-close">
<p:ajax listener="#{presupuestoBean.updateItemPresupuestoAsignado(itemPresupuesto.id,0)}"/>
</p:selectBooleanButton>
Init Method (reset to False just in case, and then assign the true values)
for (ItemPresupuesto itemsPresupuestoDefault : itemsPresupuestoDefaults) {
itemsCambiar.put(itemsPresupuestoDefault.getId(),Boolean.FALSE);
}
assign TRUE values
if (itemPresupuestoAsignado.isCambiar()) {
itemsCambiar.put(itemPresupuestoAsignado.getId(), Boolean.TRUE);
}
and
public Map<Long, Boolean> getItemsCambiar() {
return itemsCambiar;
}
My expected behavior is when the itemsCambiar has some item 'TRUE', the onIcon should be displayed. But it's not happening, all p:selectBooleanButton are displaying as offIcon.
I notice a couple of things while debugging.
The Boolean value assigned at Init, is properly assigned.
If I change the selectBooleanButton for an outputLabel, is showing 'true' (which is correct)
When I change the selectBooleanButton, and the event is fired, I can see that the 'true' value in the HashMap is not a java.lang.Boolean but a java.lang.String (attachment)
So maybe, this problem is related a cast problem, but I'm putting Boolean.TRUE in the map, so ...
any ideas?
Finally I fixed changing ui:repeat to h:datatable, (I don't know why is working).
I have created another question to request some help about it ui:repeat vs h:datatable behavior
Thanks,

Expanding behavior of Richfaces Collapsible Panel

So, I have recently started working on a JSF page using richfaces 4, in which I have a rich:collapsiblePanel. I face a problem however, I am using the collapsiblePanel within a rich:dataGrid, which renders the collapsiblePanels by iterating though a list recieved from the server. There is a link to 'sort' the collapsiblePanels according to the data in the panel header (in the backing bean of course). When any of the collapsiblePanels are expanded, and the sort link is clicked, all of them are expanded, whilst all are expanded, if one is closed, and the link clicked again, all of them close.
Things I have tried:
Changing the switchType to any other than client (i.e ajax and server)
Adding a constant boolean in the backing bean to force the expand attribute to false on reload (although it is not even affected by the backing bean at all)
Sample code of what it looks like at the moment:
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="bean.listValues" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
The link simply calls a method in the backing bean which does the sorting.
I have found a similar problem, involving a dataTable instead of a dataGrid, although no answers have been given, but only links that lead to more dead ends. This can be found at: https://community.jboss.org/message/819938
Any help would be greatly appreciated. Unfortunately I do not have alot of time to answer alot of other questions at the moment, but I will be checking back a bit later.
Thanks in advance.
You have many syntax flaws inside your code, here is how it should looks like :
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
You are probably experiencing only one collapsiblePanel in your example, this code modified and tested work properly.
Now if you want to save collapsiblePanels expanded state when refreshing your dataGrid by AJAX, you need to add some stuff.
First, you need to add one property to your objects you are iterating on, to save the state of each panels.
public class Item
{
private boolean expanded;
public void setExpanded(boolean expanded)
{
this.exanded = expanded;
}
public boolean getExpanded()
{
return this.expanded;
}
// Your other stuff
}
Second, you need to add a listener in your bean to know when user changes the state of a panel, note the attribute to get back which item is related to this panel.
#ManagedBean
#ViewScope
public class Bean
{
private List<Item> listValues;
#PostConstruct
void init()
{
listValues = //... Some initialization to your list
}
public List<Item> getListValues()
{
return this.listValues;
}
public void toggle(PanelToggleEvent event)
{
// Take the current item
Item item = (Item)event.getComponent().getAttributes().get("item");
// Save the current state in the item
item.setExpanded(event.getExpanded());
}
}
Finally, you need to change your switchType to AJAX and add the listener in your code without forgetting the attribute that need to be passed in the listener.
<h:form>
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="item"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="ajax" expanded="#{item.expanded}">
<f:attribute name="item" value="#{item}" />
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:form>

Ajax attached to Composite Component updates model but does not fire listener

I have a custom component location. I want that, when a change is done, the model is update so another component (an autocomplete) is to show only results related to the location value. Also, that component is rerendered to reset it.
I have a page with the following code (simplified):
<h:form id="ticketForm">
...
<loc:location id="locationId" <-- CUSTOM COMPONENT
hiddenFieldValue="#{ticketCtrl.ticket.location}"
visibleFieldValue="#{ticketCtrl.ticket.locationDescription}"
rendered="#{ticketCtrl.ticketModifiable}">
<f:ajax event="changeLocation" render=":ticketForm:gfhId" <-- AJAX CALL.
execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
</loc:location>
...
</h:form>
When the value in the component is changed, the model is updated and :ticketForm:gfhId is rendered as needed, but the listener(which performs additional resets) is not executed.
Attaching the ajax to a simpler control results in the listener being executed; v.g.
<h:inputText id="contactId"
value="#{ticketCtrl.ticket.contactPerson}"
disabled="#{not ticketCtrl.ticketModifiable}">
<f:ajax event="change" render=":ticketForm:gfhId"
execute=":ticketForm:locationId" listener="#{ticketCtrl.locationListener}"/>
</h:inputText>
works perfectly.
I do not know if it may be related as how the changeLocation event is fired; inside my component I define it as
<composite:interface>
...
<composite:clientBehavior name="changeLocation" event="change" targets="visibleId"/>
</composite:interface>
with visibleId being a readonly text; when it is changed by javascript I fire the change event on it with JS.
function launchEvent(fieldName) {
if ("fireEvent" in fieldName) {
fieldName.fireEvent("onchange");
} else {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
fieldName.dispatchEvent(evt);
}
}
The info I find in other questions is about making ajax an inner part of the composite component, here I want ajax detached because I probably won't need it in other uses of the component.
I am using JBoss 6.1 wih Mojarra 2.1.9 and Richfaces 4.
Thanks in advance.
UPDATE:
Even after finding jarek.jpa's answer right, if someone wants to check the code it is here:
The composite component
http://pastebin.com/9wqMVfR5
The main form
http://pastebin.com/i39ys2D9
This may have to do with the "readonly" attribute set to true. Though you manage to send the change-event by hand (JS), the server-side processing of the listener may be dropped due to the readonly state. See e.g. jsf (richfaces) readonly input text validation.

Grails: checkbox not being set back to false

I am developing a Grails (1.0.4) app where I want to edit a collection of collections on a single page in a grid view. I got it to work quite well depending only on the indexed parameter handling of Spring MVC, except for one thing:
boolean (or, for that matter, Boolean) values in the grid can be set via checkbox, but not unset, i.e. when I check the checkbox and update, the value is set to true, but afterwards when I edit again, uncheck the checkbox and update, it remains true.
This is the GSP code of the checkbox:
<g:checkBox name="tage[${indexTag}].zuweisungen[${indexMitarb}].fixiert" value="${z.fixiert}" />
And this is the HTML that is generated:
<input type="hidden" name="tage[0].zuweisungen[0]._fixiert" />
<input type="checkbox" name="tage[0].zuweisungen[0].fixiert" checked="checked" id="tage[0].zuweisungen[0].fixiert" />
I've found a Grails bug that describes exactly this effect, but it's marked as fixed in 1.0.2, and the problem mechanism described there (underscore in hidden field name is put in the wrong place) is not present in my case.
Any ideas what could be the reason?
This is the solution a guy named Julius Huang proposed on the grails-user mailing list. It's reusable but relies on JavaScript to populate a hidden field with the "false" response for an unchecked checkbox that HTML unfortunately does not send.
I hack GSP to send "false" when
uncheck the box (true -> false) with
custom TagLib.
By default checkBox send nothing when
uncheck, so I use the checkBox as
event handler but send hidden field
instead.
"params" in Controller can handle
"false" -> "true" without any
modification. eg. Everything remain
same in Controller.
The Custom Tag Usage in GSP (sample usedfunc_F is "true"),
<jh:checkBox name="surveyList[${i}].usedfunc_F" value="${survey.usedfunc_F}"></jh:checkBox>
Here is what the Tag generate,
<input type="hidden" name="surveyList[#{i}].usedfunc_F" id="surveyList[#{i}].usedfunc_F" value="false" />
<input type="checkbox" onclick="jhtoggle('surveyList[#{i}].usedfunc_F')" checked="checked" />
The Javascript
<script type="text/javascript">
function jhtoggle(obj) {
var jht = document.getElementById(obj);
jht.value = (jht.value !='true' ? 'true' : 'false');
}
</script>
This is my own solution, basically a workaround that manually does what the grails data binding should be doing (but doesn't):
Map<String,String> checkboxes = params.findAll{def i = it.key.endsWith("._fixiert")} // all checkboxes
checkboxes.each{
String key = it.key.substring(0, it.key.indexOf("._fixiert"))
int tagIdx = Integer.parseInt(key.substring(key.indexOf('[')+1, key.indexOf(']')))
int zuwIdx = Integer.parseInt(key.substring(key.lastIndexOf('[')+1, key.lastIndexOf(']')))
if(params.get(key+".fixiert"))
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = true
}
else
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = false
}
}
Works, requires no change in grails itself, but isn't reusable (probably could be made so with some extra work).
I think that the simplest workaround would be to attach a debugger and see why Grails is failing to populate the value. Considering Grails is open source you'll be able to access the source code and once you figure out the solution for it you can patch your version.
I have also found this other bug GRAILS-2861 which mentions the issue related to binding to booleans (see Marc's comment in the thread). I guess that is exactly the problem you are describing.
I would create a small sample app that demonstrates the problem and attach it to the Grails bug (or create a new one). Someone here may be able to debug your sample app or you'll have shown the bug isn't really fixed.
Try this out, set the logs to DEBUG, frist try the first 3 if they don't show the problem up, flip them all to DEBUG:
codehaus.groovy.grails.web.servlet="error" // controllers
codehaus.groovy.grails.web.pages="error" // GSP
codehaus.groovy.grails.web.sitemesh="error" // layouts
codehaus.groovy.grails."web.mapping.filter"="error" // URL mapping
codehaus.groovy.grails."web.mapping"="error" // URL mapping
codehaus.groovy.grails.commons="info" // core / classloading
codehaus.groovy.grails.plugins="error" // plugins
codehaus.groovy.grails.orm.hibernate="error" // hibernate integration
This should allow you to see exactly when and how the parameters setting is failing and probably figure out a work around.

Resources