AjaxEventBehavior behavior = new AjaxEventBehavior("keyup"){
#Override
protected void onEvent(AjaxRequestTarget target) {
System.out.println("Hello world!");
}
};
form.add(behavior);
In previous versions of Wicket I could have done it like:
behavior.setThrottleDelay(Duration.ONE_SECOND);
But since version 6.1 this opportunity has been erased. And the web is full of previous versions tutorials which all contain .setThrottleDelay() methods.
Basically, the goal is to call out the behavior when the person has stopped typing in the form. Currently it calls out the behaviour every time INSTANTLY when the key gets up which basically spams the server side. That's why I would like to delay. Background: I'm currently trying to make queries into database and get out the data which are similar to the form input. And all that in the time when the person is typing. But the delay would be needed in goal to keep server-side/SQL out of the "bombarding range".
Also I am open to alternatives.
Setting the throttle's settings has been unified with all other Ajax settings in AjaxRequestAttributes for version 6.0.0 which is a major version and was not drop-in replacement.
https://cwiki.apache.org/confluence/display/WICKET/Wicket+Ajax contains a table with all the settings, the throttling ones are mentioned at the bottom of it.
To use it :
AjaxEventBehavior behavior = new AjaxEventBehavior("keyup") {
#Override
protected void onEvent(AjaxRequestTarget target) {
System.out.println("Hello world!");
}
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
super.updateAjaxAttributes(attributes);
attributes.setThrottlingSettings(
new ThrottlingSettings(id, Duration.ONE_SECOND, true)
);
}
};
The last constructor argument is what you need. Check its javadoc.
Looking at the sources, it looks as you can get the AjaxRequestAttributes via getAttributes() and call setThrottlingSettings() on this.
Strange that the api change is not mentioned in the wiki. The announcement for 6.1 calls it an drop in replacement.
It seems that drop behavior is what you're after:
dropping - only the last Ajax request is processed, all previously
scheduled requests are discarded
You can specify a drop behavior, that will only for the Ajax channel by customizing the AjaxRequestAttributes of the behavior with AjaxChannel.DROP by means of updateAjaxAttributes, as pointed out in the wiki:
AjaxEventBehavior behavior = new AjaxEventBehavior("keyup"){
#Override
protected void onEvent(AjaxRequestTarget target) {
System.out.println("Hello world!");
}
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
super.updateAjaxAttributes(attributes);
attributes.setChannel(new AjaxChannel("myChannel", AjaxChannel.Type.DROP));
}
};
form.add(behavior);
As #bert also suggested, you can also setThrottlingSettings to the AjaxRequestAttributes.
Probably a combination of both behaviors would fit better in what you seem to need.
Related
Wicket throws StalePageException only if some Ajax action has been performed on a page before duplicating the page.
Example wicket project can be found at, along with steps to reproduce the exception.
https://github.com/rjngshn/java-wicket-testing/tree/main
Is there a way to ensure this exception is not thrown?
Thanks
Rajani
The default behavior provided in Wicket is too queue AJAX requests as they come in. Let’s say you have a button with a callback that does some work when clicked and updates the UI. This means that if the button is quickly clicked three times successively, the last two requests will be queued up and processed after the first request finishes.
A simple solution is to change the behavior of the AjaxChannel from queueing to active. This means that if any AJAX requests are received while there is an active(unfinished) request being processed, they will be ignored.
So how do we override Wicket’s default behavior in one spot and ensure all AjaxChannel‘s are modified? We use a custom AjaxRequestTarget.IListener.
public class ActiveAjaxListener implements AjaxRequestTarget.IListener {
private static final AjaxChannel ACTIVE_CHANNEL = new AjaxChannel(AjaxChannel.DEFAULT_NAME, AjaxChannel.Type.ACTIVE);
#Override
public void updateAjaxAttributes(AbstractDefaultAjaxBehavior behavior, AjaxRequestAttributes attributes) {
attributes.setChannel(ACTIVE_CHANNEL);
}
}
Our ActiveAjaxListener class will modify every AJAX behavior and make sure it uses the active channel. To register it, we simple insert this line into our WebApplication init() method:
getAjaxRequestTargetListeners().add(new ActiveAjaxListener());
(I've copied this explanation from https://www.coderdreams.com/wicket-quick-tip-4-change-default-ajaxchannel-to-active/)
Another way is to use a veil that prevents the double clicks via JS/CSS. More details about this approach could be found at JavaScript / Wicket : How to display an overlay which prevents user interaction
I'm new to web dev and I'm trying Thymeleaf template engine on App Engine. It has worked fine so far, except I always get java IllegalAccessException's when I attempt method (as opposed to simple attribute) access.
For example, with this line of HTML:
<div class="panel" th:id="${item.getWebId()}">
I get:
java.lang.IllegalAccessException:
Method [public java.lang.String myapp.ItemInfo.getWebId()] cannot be accessed.
at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:851)
This happens both on dev server (Win Vista) and in production with GAE SDK's 1.9.0 and 1.8.9. I've tried the current TL (2.1.2) and the previous version (2.0.20). I'm not using Spring.
I've found others having reflection problems (here and here) on the TL forum, but nothing that helps.
Some people using Struts or Spring encountered similar problems a long time ago, and resolved them by setting OgnlRuntime.setSecurityManager(null). I haven't pursued this because I can't see how to access the OgnlRuntime object in TL, and it doesn't make much sense to me that I would be the only TL user to need this.
Looking at OgnlRuntime v3.0.6 (here) it looks like the easiest solution would be to disable 'checkPermission', but again, as someone new to TL, I'm hesitant to make a change that TL doesn't expose, and that no one else using TL seems to need to do. There must be something else wrong?
In the end I proceeded with the OgnlRuntime.setSecurityManager(null) option. It seems like a bad idea but it allows me to proceed for now.
Here's the code I used:
public class MyContextListener implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent arg0) {
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
OgnlRuntime.setSecurityManager(null);
}
}
And in my web.xml I added:
<listener>
<listener-class>com.myapp.MyContextListener</listener-class>
</listener>
I'm a fairly experienced Wicket user but I'm making my first foray into 1.5 and the mountPage() syntax is defeating me.
I'm clearly doing something wrong because I can't fine a single reference of someone having this same issue. So here it goes:
This is what I have in my init() method:
#Override
public void init()
{
super.init();
System.out.println("mounting: /requirement/${id}");
mountPage("/requirement/${id}", RequirementPage.class);
}
I've verified this is working by changing the "requirement" part to other things and back. This is the (only) constructor for RequirementPage:
public RequirementPage()
{
try
{
PageParameters params = getPageParameters();
System.out.println("named keys: " + params.getNamedKeys());
System.out.println("index keys: " + params.getIndexedCount());
StringValue value = params.get("id");
System.out.println("requirement: " + value);
In my server console (Jetty8) I see this on startup:
mounting: /requirement/${id}
And when I make a request to /requirement/0 I see this:
named keys: []
index keys: 0
requirement: null
I've looked at a number of things and I can't see anything different about what I am doing from what the wiki, or other examples show.
Any help is appreciated.
thanks,
-James
You need to provide Wicket a constructor with PageParameters, otherwise there's no possibility for wicket to wrap those parameters and provide it to your page.
Apart from that, you can access requestparameters via getRequestCycle().getRequest().getRequestParameters() without having a constructor with pageparameters, but as far as youd like wicket to manage and mount your pages and parameters and having them bookmarkable, it is necessary to provide a default constructor, with or without pageparameters, occording to your requirement of recieving parameters or not.
You can try this;
#Override
public void init()
{
super.init();
mountPage("requirement", RequirementPage.class);
}
Then call the url like this "http://localhost:8080/requrement?id=111" And then you can get id with your constructor. But you can use your web page constructor like this;
public RequirementPage(PageParameters parameters)
{
...
}
HI guys,
I wanted to add an AJAX Event to my Homepage, but it doesn't work! I figured out, that if I delete the onComponentTag function it works well. I have no clue why this happend, maybe you can help me!
Thats my Code:
final TextField<String> searchInput = new TextField<String>("searchInput", model) {
#Override
protected void onComponentTag(final ComponentTag tag) {
super.onComponentTag(tag);
tag.put("id", this.getId());
if (params.getString("search") != null) {
tag.put("value", params.getString("search"));
}
}
};
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.addComponent(searchInput);
}
});
Thx a lot for helping me!
CU
Firstly, you don't need to be overriding onComponentTag() at all. As seanizer states, if your really need to specify a markup ID yourself, use setMarkupId(id). You should understand why it is recommended that Wicket manages component IDs.
Secondly, the value attribute that you are adding is unnecessary - Wicket adds this automatically for this component. The value assigned is the value of the component's model object. See the source for TextField.onComponentTag().
Thirdly, again as seanizer states, components that are to be updated by ajax need to output their markup IDs - Wicket's ajax implementation uses the ID as the selector for the element. Additionally, all Wicket ajax behaviours that extend AbstractDefaultAjaxBehavior automatically set outputMarkupId(true) on the component they are bound to (see the source for AbstractDefaultAjaxBehavior.onBind()). This includes AjaxFormComponentUpdatingBehavior.
So:
String id = "searchInput";
final TextField<String> searchInput = new TextField<String>(id, model);
searchInput.setMarkupId(id);
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.setOutputMarkupId(true);
target.addComponent(searchInput);
}
});
Finally, I'd question what you're actually trying to achieve with this behaviour. I don't see any reason to round-trip this event to the server. Surely some client-side JS is more appropriate?
tag.put("id", this.getId());
is not the way to do it in wicket.
instead, use
component.setOutputMarkupId(true)
(either in your component constructor or in your behavior's bind() method) to make wicket write the id, and if you absolutely need to control what the id is (which is almost never the case) you can do
component.setMarkupId("myId")
also, you probably shouldn't assign the tag value yourself, use a model (model handling is extremely smart in wicket, read more about models). There are valid uses for onComponentTag, but they are way beyond what you are doing. Let wicket do what wicket does best and everything will be fine.
EDIT:
OK, some more clarification
have a look at the source code of AjaxFormComponentUpdatingBehavior, especially the part where the javascript event handler is generated.
protected final CharSequence getEventHandler()
{
return generateCallbackScript(
new AppendingStringBuffer("wicketAjaxPost('")
.append(getCallbackUrl(false)).append(
"', wicketSerialize(Wicket.$('"
+ getComponent().getMarkupId() + "'))"));
}
as you can see, wicket uses getMarkupId() to determine the actual id. The id you set using tag.put(id) is totally unknown to wicket and hence the behavior cannot work.
The standard thing to do is setOutputMarkupId(true). This is the only proper way to tell wicket to render the id (other than setOutputMarkupPlaceholder(true), which internally calls the former method). That way you make sure that the id wicket writes is the id wicket knows about. If this doesn't render the id, you are probably breaking some default behavior by overwriting onComponentTag.
Have a look at the source code of Component, especially at onComponentTag(), the method you are overriding:
protected void onComponentTag(final ComponentTag tag) {
// if(setOutputMarkupId(true) was set)
if (getFlag(FLAG_OUTPUT_MARKUP_ID)) {
// set id attribute
tag.put(MARKUP_ID_ATTR_NAME, getMarkupId());
}
}
[The comments are mine. BTW, this is the source of an ancient version, but I didn't find any current source online, and the functionality hasn't changed.]
Now if, as in your case, you want to set the component id manually, you must use
component.setMarkupId("myId")
and of course
setOutputMarkupId(true)
as well. If that doesn't work, go to the wicket JIRA site and file a bug. But I doubt it, this is standard functionality that works for thousands of users.
I am using the org.eclipse.ui.popupMenus extension point for adding a sub-menu whose Action that is bounded to the following class:
public class MyAction implements IObjectActionDelegate {
private Logic logic = Logic.getInstance(); // Singleton
public void setActivePart(IAction a, IWorkbenchPart targetPart) {
// Nothing here
}
public void run(IAction a) {
// Do something...
}
public void selectionChanged(IAction a, ISelection s) {
a.setEnabled(logic.isEnabled(s));
}
}
This action is working correctly in most cases (including the call a.setEnabled() in selectionChanged()).
My problem at the very first time my action is being invoked. The selectionChanged method is called only after the menu item has been displayed (and not when the user has made the selection) which means that the call to a.setEnabled() will have no affect.
Any ideas on how to make my action receive selectionChanged() notifications even before the fist time it is being invoked?
Eclipse uses so-called lazy plugin activation, so it first derives as much as possible from plugin.xml, and the behaviour you are observing is well-documented in the API. See this related question.
The words first time and after make me wonder about a synchronization problem. If the initialization of Logic.getInstance() is deferred, you might look at the Initialization On Demand Holder Idiom, also discussed in item 71 of Effective Java.