ZK - EventQueue working, but data not refreshing - events

Ok, so I have spent way too much time on this already, but it is really bugging me! So, I have a page with a bunch of tabs on it. To keep things manageable, I want to turn each of those tabs into their own .zul page with their own ViewModel. I have implemented an EventQueue in order to pass the main object (the Tournament object) from the main page to all of the sup-pages.
The problem is, whenever the event is fired and it updates the Tournament object, the page will not refresh its data even though it has changed in the ViewModel. I have tried adding the #NotifyChange annotation with no success. While debugging, I have eliminated the extra .zul. See code below.
tournamentsTab.zul:
<tabpanel apply="org.zkoss.bind.BindComposer" viewModel="#id('bcvm') #init('com.cannon.tnt.trm.mvvm.BeltClassViewModel')">
<vlayout vflex="1">
<grid model="#load(bcvm.tournament.beltClasses)" emptyMessage="No belt ranks created yet." vflex="1">
<columns>
<column label="Name" align="center" width="200px"/>
<column label="Description" align="center"/>
<column label="Delete" align="center" width="120px"/>
</columns>
<template name="model">
<row>
<textbox value="#bind(each.name)" width="95%" onChanging="#command('setStateEditing')"/>
<textbox value="#bind(each.description)" width="95%"
onChanging="#command('setStateEditing')"/>
<button label="Delete" onClick=""/>
</row>
</template>
</grid>
</vlayout>
<!--<include src="beltClassPanel.zul"/>-->
</tabpanel>
BeltClassViewModel.java:
public class BeltClassViewModel {
private EventQueue eq;
private Tournament tournament;
#Init
public void init() {
eq = EventQueues.lookup("tournamentQueue");
eq.subscribe(new EventListener() {
public void onEvent(Event event) throws Exception {
setTournament((Tournament) event.getData());
}
});
}
public Tournament getTournament() {
return tournament;
}
#NotifyChange("{tournament}")
public void setTournament(Tournament selectedTournament) {
this.tournament = selectedTournament;
}
}
As I mentioned, the EventQueue part is working perfectly. The event is being fired and then received by the listener who makes the call to set the tournament object on the view model. The problem is, the referenced tournament object is not being updated in the UI. I have put a break point in the getTournament() call and verified that the ONLY time that gets called is when the page first loads.
PLEASE HELP!!! I know that usually these things are just something stupid I'm overlooking. Please prove my idiocy! :)

I suppose that you need to post notification manually, you can try something like this:
public void onEvent(Event event) throws Exception {
setTournament((Tournament) event.getData());
BindUtils.postNotifyChange(null, null, BeltClassViewModel.this, "tournament");
}

Eugene found the problem. A simple mistake. I had #NotifyChange("{tournament}") when it should have been #NotifyChange({"tournament"}). Thanks, Eugene and Stack Overflow!

Related

Primefaces p:cache

I'm having some problem with Primefaces p:cache component
This is example how its used on testpage/index.xhtml
<h:form>
<p:panel header="Testsite">
<p:cache region="testsite2"
key="testsite2#{user.id}#{user.defaultLanguage}">
<p:commandButton action="#{testBean.hello}" value="btn"
rendered="#{testBean.renderedButton}">
</p:commandButton>
</p:cache>
</p:panel>
</h:form>
and this is back end bean
#ManagedBean(name = "testBean")
#ViewScoped
public class TestBean {
#PostConstruct
public void init() {
System.out.println("init");
}
public void hello() {
System.out.println("hello");
}
public boolean isRenderedButton() {
System.out.println("isRenderedButton");
return true;
}
}
So on first page hit init and isRenderedButton message are printed normally as expected. After that when I click on button I do expect to see hello message printed, but that's not case here. Can anyone point me in right direction ?
According to Primefaces showcase for p:cache with buttons I was expecting this behavior.
Right now I am using Primefaces.DEFAULT_CHACHE_PROVIDER and later I will switch to ehcache.
I'm using PF 5.3, sun faces 2.2.12.
Thanks.
To answer myself (and maybe ill help someone), i was trying to create dynamic menu from database and i wanted to cache generated content with p:cache component. But back then every menu item would call bean method which would redirect user to page and that was problem in first place.
So i had something like this:
<p:menu>
<p:submenu label="Human resource">
<p:menuitem value="Search person" actionListener="#{bean.navigateUserToSearchPerson}"/>
</p:submenu>
I actually did not fix this problem (had no extra time to investigate problem), so i came up with idea to generate links for each menu item, so when user clicks on menu item, it would redirect him to new page. So now i don't have any AJAX calls in menu and caching works fine now.
Code example:
<p:cache region="appUiCache" key="panelMenu#{user.id}#{user.defaultLanguage}">
<p:panelMenu id="sm" model="#{bean.menuModel}" stateful="true" />
</p:cache>
Menu items are created dynamically from database:
DefaultMenuItem defaultMenuItem = new DefaultMenuItem(...);
defaultMenuItem.setIcon(item.getIcon());
defaultMenuItem.setUrl(item.getUrl()); <!-- This is new url part -->
This works fine now in production. Thanks.

Unable to locate ajax zone for dynamic update

I'm fairly new to Tapestry, and I'm trying to update a zone when selecting a value from a select component. This is where I'm trying to do that:
<t:Zone t:id="ispTypeZone" id="ispTypeZone">
<t:Select t:id="ispType"
t:blankLabel="[${message:select-label}]" t:zone="ispTypeZone"
t:value="ispType" event="valueChangedFromIspType"
disabled="${editable}" style="width:515px;"
t:blankOption="ALWAYS" t:validate="required"
/>
</t:Zone>
<t:Zone t:id="selectionZone" id="selectionZone">
<t:If t:test="${somethingSelected}">
<t:If test="${ispSelected}">
<t:Zone t:id="ovZone" id="ovZone">
<t:Select t:id="ovType" t:value="ovType"
t:blankLabel="[${message:select-label}]" t:zone="ovZone"
t:validate="required" event="valueChangedFromOvType"
style="width:515px;" />
</t:Zone>
<p:else>
<t:Zone t:id="vpZone" id="vpZone">
<t:Select t:id="vpType" t:value="vpType"
t:blankLabel="[${message:select-label}]" t:zone="vpZone"
t:validate="required" event="valueChangedFromVpType"
t:blankOption="ALWAYS" disabled="${editable}"
style="width:515px;" />
</t:Zone>
</p:else>
</t:If>
<p:else>
</p:else>
</t:If>
</t:Zone>
This is where I call the render:
void onValueChangedFromIspType(String ispType) {
//some code here
if (request.isXHR()) {
ajaxResponseRenderer.addRender(selectionZone);
}
}
Whatever the value selected from the select component, it triggers a render for selectionZone, but I keep getting an error message "Unable to locate Ajax Zone 'selectionZone' for dynamic update". Despite the error message, 'somethingSelected' is still being executed, but the following select components are not being displayed. I can't seem to find the problem, so if anyone could point me in the right direction, I would appreciate it.
Thanks.
If your ispType select change have to update something in selectionZone, then t:zone should selectionZone and not ispTypeZone.
In your class, declare your zone :
#InjectComponent
private Zone selectionZone;
In your onValueChange method a simple return should be enough :
void onValueChangedFromIspType(String ispType) {
//some code here
if (request.isXHR()) {
return this.selectionZone;
}
}

ZK MVC : how can i wait till the compose of another componant

i m working on a ZK project , using ZK MVC approach. what i did try to do is to initalize "a panel" after doAfterCompose a div , but the problem is that i got a "java.lang.NullPointerException"
and those are a simple exemple of what i did try to do . My view "mypage.zul"
<zk>
<borderlayout>
<west width="140px" splittable="true" collapsible="true" maxsize="140">
<div align="center" apply="dashboard.display">
<label value="WorkLoad"></label><checkbox></checkbox>
</div>
</west>
<center autoscroll="true" >
<div>
<portallayout id="portalLayout" maximizedMode="whole" width="100%" >
<portalchildren >
<panel id="panelworkload" >
<panelchildren>
<div width="100%" >
<charts id="workloadDay" type="column" />
</div>
</panelchildren>
</panel>
</portalchildren>
</portallayout>
</div>
</center>
</borderlayout>
</zk>
My conroler : "display"
public class display extends SelectorComposer<Div>{
#Wire
Checkbox objectif_checkbox;
#Wire
Panel panelworkload;
public void doAfterCompose(Div comp) throws Exception {
super.doAfterCompose(comp);
panelworkload.setTitle("hello workload");
}
}
and this is the exception that i got
java.lang.NullPointerException dashboard.display.doAfterCompose(display.java:24)
dashboard.display.doAfterCompose(display.java:1)
org.zkoss.zk.ui.impl.UiEngineImpl.doAfterCompose(UiEngineImpl.java:578)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:880)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:826)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:735)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:699)
what i have throught of it so far is that the div has been composed before the portallayout , that why the server cant reconize portallayout when div is created
can anyone help me pls ? i m kinda stuck here ...and thank you
The setTitle method for zk framework's Panel object is the following:
public void setTitle(String title) {
if (title == null)
title = "";
if (!Objects.equals(_title, title)) {
_title = title;
smartUpdate("title", _title);
}
}
There is nothing in there that would throw a NullPointerException. (And the stack trace would indicate it)
Therefore, the panelworkload should currently be null in the doAfterCompose(comp) object.
I would recommend you read through several of the answers on What is a NullPointerException, and how do I fix it? , although they do not do a great job of explaining how to diagnose a NullPointerException error, nor how to follow a stack trace.
Panel Source Reference

ActionSupport not getting triggered

My action support is not getting triggered at all when I put it in my VF page. I looked at similar problems and changing the events but nothing seems to be doing the trick.
//suppose my object is called coffecup. This is a generic code, there may be small syntax error although probably not the problem.The rerender attribute rerenders coloumns on the pageblock table holding the coffecupSize and coffecupshape fields.The debug log shows that the setCoffeeCupSizeandShape method is not being entered at all
VF
<apex:column rendered="{!ifaccesible}">
<apex:facet name="header">Coffee Cup Colours</apex:facet>
<apex:outputField value="{!coffecup.colours}"> //A lookup field on the custom object
<apex:actionSupport event="onchange" action="{!setCoffeeCupSizeandShape}" rerender="coffecupSize, coffecupShape" />
<apex:inlineEditSupport />
</apex:outputField>
</apex:column>
Controller
public void setCoffeeCupSizeandShape
{
if (coffecup.colour == red)
CoffeeCupSize = large;
coffeeCupShape = round;
}
apex:outputField has no onchange event support. You need to use apex:inputField.
If you need apex:outputField here, look at this answer

View scope reset fields to default after performing an action

First of all, my beans are managed by spring not by JSF and I am using custom view scope as described in this article. So if the behavior is weird for regular JSF2 and might be related to Spring, please tell me.
Bean:
public class DepartmentBean {
private DefaultTreeModel model;
public void preRender(ComponentSystemEvent event) throws Exception {
if (model == null) {
model = myService.buildModel();
}
}
public String clear() {
// resetting stuff
return "pretty:";
}
}
View:
<h:form>
<ice:panelGroup styleClass="crud-links">
<h:commandLink value="Delete" action="#{department.deleteDepartment}" />
</ice:panelGroup>
</h:form>
<h:form>
<ice:panelGroup>
<ice:tree id="tree" value="#{department.model}" var="item" hideRootNode="false" hideNavigation="false" imageDir="./xmlhttp/css/xp/css-images/">
<ice:treeNode>
<f:facet name="content">
<ice:panelGroup style="display: inline">
<ice:commandLink value="#{item.userObject.text}"></ice:commandLink>
</ice:panelGroup>
</f:facet>
</ice:treeNode>
</ice:tree>
</ice:panelGroup>
</h:form>
When page is loaded for first time the model object is populated with data, but when clicking delete button I notice that after clearing preRender() method is executed and the model (which was populated before clearing becomes null, and gets populated again, although I am in same page, and it should maintain the value)
Does the code have a problem that leads to such behavior, or this is the normal behavior?
If the problem maybe related to Spring or the custom view scope or the IceFaces, please advise.
UPDATE- REQUIREMENT:
I want to initialize the tree model on construction of the page, and while i am still on the page the tree model doesn't gets initialized again until i do that programatically .
oh my mistake, initialization should be inside #PostConstruct.

Resources