-
FEATURED COMPONENTS
First time here? Check out the FAQ!
Hello colleagues,
I have the following problem:
I have various tabs for different groups of properties of resources that can be edited in forms on these tabs. Some of the tabs require unsaved changes to be applied or discarded before switching to certain other tabs. To implement this, I assigned the tabs to groups. Whenever the tab group changes, I open a dialog and ask the user to apply, discard, or cancel. Everything works fine now except that the tab is switched independently of my dialog.
So what I need to do is somehow intercept the the select-event sent to the tab(box) so that selectTabDirectly(...) is not called on the tab box if the user cancels switching of the tab. Does anyone know how to achieve that?
Thanks beforehand,
David
I had the same thing to implement and that's what i did:
1 - made my own implementation of org.zkoss.zk.ui.util.EventInterceptor interface... let's call this TabboxEventInterceptor
2 - registered the interceptor in the desktop with Executions.getCurrent().getDesktop().addListener(new TabboxEventInterceptor())
Then you are able to intercept all the events you need before or after they are processed or event posted: if you want to stop the event because there are pending chances... you can just return null as event instrade of returning the original one and that's it!
First of all, thanks for the prompt advice. However, it doesn't seem to work. The tab switches before the interceptor is called. Here is my interceptor:
private class TabSelectEventInterceptor implements EventInterceptor { @Override public Event beforeSendEvent(Event event) { LOG.info("beforeSendEvent"); return event; } @Override public Event beforePostEvent(Event event) { LOG.info("beforePostEvent"); if ( event instanceof SelectEvent && event.getTarget() instanceof Tab && event.getTarget().getId().equals("mNodes")) { return null; } return event; } @Override public Event beforeProcessEvent(Event event) { LOG.info("beforeProcessEvent"); return event; } @Override public void afterProcessEvent(Event event) { LOG.info("afterProcessEvent"); } }
Apparently, the tab is switched already on the client side before / in parallel to sending the request to the server. Event if I put a breakpoint int DHtmlUpdateServlet.service(req, res), the tab switches before anything else happens. Probably, I need to override the javascript?
Cheers,
David
Hi David,
i said that i had to do the same thing but that i've checked... it's not true: my concern was about closable tabs and pending changes: in that case Tabbox & EventInterceptor are working fine.
In case of selection instead i confirm your problem: it seems that even returning a null event... the selection of tab is processed absolutelly BEFORE the interceptor is triggered.
@Override public Event beforePostEvent(Event event) { if (event instanceof SelectEvent && event.getTarget() instanceof Tab) { Tab t = (Tab) event.getTarget(); Tabbox tb = (Tabbox) t.getParent().getParent(); System.out.println(tb.getSelectedIndex()); return null; } return event; }
In fact when beforePostEvent is called.... the selected index of the Tabbox is changed already. Meh!
Hi David,
It can be done by override doClick_ method of tab,
please refer to the sample below.
<zk>
<script type="text/javascript"><![CDATA[
zk.afterLoad("zul.tab", function () {
var originClick = zul.tab.Tab.prototype.doClick_;
var originUnbind = zul.tab.Tab.prototype.unbind_;
zul.tab.Tab.prototype.doClick_ = function (evt) {
if (this._preventSelect) {
evt.stop();
return;
}
originClick.apply(this, arguments);
}
zul.tab.Tab.prototype.unbind_ = function () {
this._preventSelect = null;
originUnbind(this, arguments);
}
});
]]></script>
<tabbox id="tabbox" width="400px">
<tabs id="tabs">
<tab id="tabOne" label="tabOne" closable="true" />
<tab id="tabTwo" label="tabTwo" closable="true" />
</tabs>
<tabpanels id="tabpanels">
<tabpanel id="panelOne">
panel one
</tabpanel>
<tabpanel id="panelTwo">
panel two
</tabpanel>
</tabpanels>
</tabbox>
<checkbox label="prevent select tab1">
<attribute name="onCheck">
if (self.checked)
Clients.evalJavaScript("zk.Widget.$(jq('$tabOne')[0])._preventSelect = true");
else
Clients.evalJavaScript("zk.Widget.$(jq('$tabOne')[0])._preventSelect = null");
</attribute>
</checkbox>
<checkbox label="prevent select tab2">
<attribute name="onCheck">
if (self.checked)
Clients.evalJavaScript("zk.Widget.$(jq('$tabTwo')[0])._preventSelect = true");
else
Clients.evalJavaScript("zk.Widget.$(jq('$tabTwo')[0])._preventSelect = null");
</attribute>
</checkbox>
</zk>
Regards,
ben
Hi All,
I have done it in a different way. For your reference:
package j23b6j9g$v2;import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.ForwardEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Tab;public class TestComposer extends GenericForwardComposer {
public void onSwitchTab(ForwardEvent event) throws InterruptedException {
final Tab tab = (Tab) event.getOrigin().getTarget();
Messagebox.show("Are you sure to leave?", "Exit",
Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION,
new EventListener() {public void onEvent(Event event) throws Exception {
String evtName = event.getName();if (Messagebox.ON_OK.equals(evtName)) {
tab.setSelected(true);
} else if (Messagebox.ON_CANCEL.equals(evtName)) {
//do nothing
}}
});}
}
<zk xmlns:w="client">
<script type="text/javascript"><![CDATA[
function switchTab(notify, init){
if (this.desktop && !init && notify)
zAu.send(new zk.Event(this, 'onSwitchTab'));
else
this.$_sel(notify, init); //call the original method
}
]]></script>
<window apply="j23b6j9g$v2.TestComposer">
<tabbox width="300px">
<tabs>
<tab label="tab 1" w:_sel="switchTab" forward="onSwitchTab=onSwitchTab"/>
<tab label="tab 2" w:_sel="switchTab" forward="onSwitchTab=onSwitchTab"/>
</tabs>
<tabpanels>
<tabpanel>
<window title="win1" border="normal"></window>
</tabpanel>
<tabpanel>
<window title="win2" border="normal"></window>
</tabpanel>
</tabpanels>
</tabbox>
</window>
</zk>
Whoa!
That's usable! thanks Jimmy!
Hello Jimmy,
this solution looks great. However, I still got problems. I get this exception:
15.12.2011 17:27:28 org.zkoss.zk.ui.impl.UiEngineImpl handleError:1353 FATAL: >>org.zkoss.zk.ui.UiException: Only one child is allowed: <West gBHQo1#mWest> >> at org.zkoss.zul.LayoutRegion.beforeChildAdded(LayoutRegion.java:343) >> at org.zkoss.zk.ui.AbstractComponent.insertBefore(AbstractComponent.java:1129) >> at org.zkoss.zk.ui.impl.AbstractUiFactory.newComponent(AbstractUiFactory.java:96) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:808) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:777) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:686) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:748) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:708) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:650) >> at org.zkoss.zk.ui.impl.UiEngineImpl.createComponents(UiEngineImpl.java:1026) >> at org.zkoss.zk.ui.impl.AbstractExecution.createComponents0(AbstractExecution.java:253) >> at org.zkoss.zk.ui.impl.AbstractExecution.createComponents(AbstractExecution.java:245) >> at org.zkoss.zk.ui.Executions.createComponents(Executions.java:179) >> at com.tailor.gui.LayerComposer.doAfterCompose(LayerComposer.java:87) >> at org.zkoss.zk.ui.impl.UiEngineImpl.doAfterCompose(UiEngineImpl.java:523) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:831) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:777) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:686) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:748) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:708) >> at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:650) >> at org.zkoss.zk.ui.impl.UiEngineImpl.createComponents(UiEngineImpl.java:1026) >> at org.zkoss.zk.ui.impl.AbstractExecution.createComponents0(AbstractExecution.java:253) >> at org.zkoss.zk.ui.impl.AbstractExecution.createComponents(AbstractExecution.java:245) >> at org.zkoss.zk.ui.Executions.createComponents(Executions.java:179) >> at com.tailor.gui.CenterStage.putOnDesktop(CenterStage.java:139) >> at com.tailor.gui.explorers.ExplorerUtils.createLayers(ExplorerUtils.java:127) >> at com.tailor.gui.listener.SwitchExplorerListener.onEvent(SwitchExplorerListener.java:90) >> at com.tailor.gui.listener.SwitchExplorerListener.onEvent(SwitchExplorerListener.java:1) >> at org.zkoss.zk.ui.AbstractComponent.onEvent(AbstractComponent.java:2706) >> at org.zkoss.zk.ui.AbstractComponent.service(AbstractComponent.java:2675) >> at org.zkoss.zk.ui.impl.EventProcessor.process(EventProcessor.java:143) >> at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.process0(EventProcessingThreadImpl.java:534) >> at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.run(EventProcessingThreadImpl.java:461) 15.12.2011 17:27:29 org.zkoss.zk.ui.impl.DesktopImpl service:715 FATAL: [Desktop z_uws:/index.zul] client error: Failed to process setAttr Cannot read property 'style' of undefined (TypeError)
What am I doing wrong?
Thanks beforehand,
David
To illustrate Matze2's point:
FAIL
<borderlayout> <west> <label value="XXXXXX"/> <textbox /> </west> </borderlayout>
Good
<borderlayout> <west> <div> <label value="XXXXXX"/> <textbox /> </div> </west> </borderlayout>
Just wrap your code in the west section with a <div> so it only "sees" one child.
Hope that helps.
Todd
Asked: 2011-12-09 11:46:10 +0800
Seen: 750 times
Last updated: Jan 21 '13