Wicket AJAX + OnComponentTag - java

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.

Related

How to set a user defined language in Xpages

In my xpage I need to set a user defined language before the page loads. the language to be set is stored in a document in the database
so I do this in beforePageLoad
var lang = getUserDoc().getItemValueString("Language")
facesContext.getViewRoot().setLocale(new java.util.Locale(lang));
context.reloadPage();
the problem is that if I do not do context.reloadPage the language is not set.
but context.reloadPage gives all kind of other problems when loading the page so
I need to find a better way.
is there anyway I can set the language of the page without reloading the page.
This doc suggests using context.setLocale/setLocaleString instead of viewRoot.setLocale. The advantage is that the context locale is used for the rest of the browser session. The context locale will be set as the viewRoot locale when any subsequent viewRoots are loaded, so you don't have to re-set the locale for every page. It does still require a context.reloadPage for the current viewRoot though, so its not exactly what you were asking for.
The doc is:
Locale use in XPages: Programmatically setting the locale
Hope I have got it correctly, just extending my answer to Per Henrik's solution here (based on the last comment), for setting the resource bundle correctly probably you can just compute it? Something like this?
<xp:this.resources>
<xp:bundle var="application">
<xp:this.src><![CDATA[#{javascript:if(context.getLocale()=="en_US")
return "/application.properties";
else
return "/application_de.properties";}]]></xp:this.src>
</xp:bundle>
</xp:this.resources>
I have just used the context variable here, but I am sure that the document variable is accessible too.
Hope this helps.
The problem is beforePageLoad runs too late - the components have already been loaded into the component tree with the relevant language.
It may work if you use a ViewHandler, as in Jesse Gallagher's Scaffolding framework on OpenNTF. You would definitely need to identify the language before the call to super.createView() though.
To use beforePageLoad, I think you would subsequently need to iterate through controls and amend the labels etc.
Setup a phase listener that sets the appropriate locale based on the user's configuration.
See this blog post by Sven Hasselbach for more details: http://hasselba.ch/blog/?p=649
I use this approach in several apps using the following phase listener based on the approach from Sven. The code reads the locale from a user bean:
public class LocalizationSetter implements PhaseListener {
private static final long serialVersionUID = -1L;
public void afterPhase(PhaseEvent event) {
}
public void beforePhase(PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
UIViewRoot view = facesContext.getViewRoot();
view.setLocale(User.get().getLocale());
}
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
}

Can I access property keys with Selenium on a wicket generated html page?

I am trying to automate frontend tests with Selenium for a wicket based web application.
Therefore I have:
- Different languages
- language property files (submit.signup.form=Submit) and wicket messages () using them
- HTML pages which are generated by wicket (input type:button and value:Submit)
If I go ahead and automate a test case with that, it will work properly.
The problems start when somebody decides to change the property file to f.i. submit.signup.form=Send.
If that happens I will have to adjust all Selenium tests to check for the correct label again to make a test successful (this is not really applicalbe for that example but for error messages it will be a problem)
Now the question:
Is there a way to make wicket to put the property key onto/into the generated html files?
Desired benefit:
I can use Java and make Selenium take the property ke and check the property file for the text. That way a change of a label in the property file would not effect the Selenium tests at all and would make it much more easy to handle.
I am grateful for any answer. :)
Best regards
By default, Wicket starts in development mode. In development mode you should see the wicket tags, you should take a look in to IDebugSettings
, however you will not see the properties gathered from the java code, but you can add the key as attribute, for example
new Label(getString("propertieKey")).add(new AttributeAppender("key","propertieKey"))
It's quite easy to do actually.
Put in your application init method:
getResourceSettings().getStringResourceLoaders().add(0, new NoResourceLoader());
Implement NoResourceLoader:
public class NoResourceLoader implements IStringResourceLoader {
#Override
public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, String variation) {
if ("noProperties".equals(style)) {
return key;
}
return null;
}
#Override
public String loadStringResource(Component component, String key, Locale locale, String style, String variation) {
if ("noProperties".equals(style)) {
return key;
}
return null;
}
}
This resource loader just returns the key if the style is set to noProperties. As it returns null, the localizer will try the next resourceloader for any other invocation.
In order to set style to "noProperties" I'd suggest adding a parameter check to your pages' constructor that would set the style on the session object when you call your application with the parameter.
public BasePage(PageParameters pp) {
String style = pp.get("st").toOptionalString();
if (style != null) {
getSession().setStyle("noProperties");
}
It would be enough to call your first url with this parameter set, then you should walk through the whole session with property keys instead of values in the html. I'd also disable this check when the app is running in production.

Wicket 6.1 AjaxEventBehavior - how to set delay?

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.

Example of Passive View design pattern using JSP and POJOs

Im trying to understand how the Passive View design pattern works for simple web apps.
Can someone provide a simple example of this pattern using these requirements:
View is a JSP that prints HELLO WORLD!
Data is persisted in the data store as "hello world", call to retrieve data can be a stub
Provide example files for pieces (presenter, view, etc) and denote which piece of the pattern each file represents.
No frameworks/DSLs should be used other than jstl/el (which are optional)
Thanks
UPDATE 1: Adding my understanding of how this would be structured.
// Presenter; responsible for multiple "rendtions" of a particular view (show, index, edit, summary, etc.)
public class HelloWorldPresenter {
private HttpServletRequest request;
private DataStore dateStore;
public HelloWorldPresenter(HttpServletRequest request) {
this.request = request;
this.dataStore = DataStoreUtil.getDataStore(request);
// Do a bunch of other inits that all getXXXModels() will use
}
public getShowModel() {
HelloWorldShowModel model = new HelloWorldShowModel();
String tmp = makeLoud(this.dataStore.getMyData()); // Stub method
model.setText(tmp);
return model;
}
private String makeLoud(String str) {
return str.toUpperCase() + "!";
}
}
// Model used by view
public class HelloWorldShowModel {
private String text;
public getText() { return this.text };
public setText(String text) { this.text = text; }
}
// View
show.jsp
<c:set var="model" value="new HelloWorldPresenter.getShowModel()"/>
${model.text} -> HELLO WORLD!
or
<% HelloWorldShowModel model = new HelloWorldPresenter(request).getShowModel() %>
<%= model.getText() %>
The things I'm unsure about are:
How the Presenter would be exposed to the View (JSP) since the View shouldnt know about the presenter. I may be mixing semantics though, and the HelloWorldShowModel (which is acting as a "ViewModel" of sorts, is what shouldnt know about the Presenter).
Should I even have the HelloViewShowModel abstraction, or should I simply have a method getText() on my Presenter which is called within the JSP to get the requested text.
If I do have multiple "views" for a resource (ex. Show, Index, Edit, Summary, etc.), should I have multiple Presenters? How should this logic be broken up? Multiple presenters that inherit from a Shared presenter? Should each presenter only be responsible for returning one ViewModel?
I've read through Fowlers articles as well as a number of other write-ups - the problem (for me) is they are written in the context of .NET apps, and I dont understand how all their objects get wired up.
I hope this will aleve concerns of me being "lazy" and looking for a "hand-out" answer :)
With the requirements you state I would say the pattern can't be implemented. If you consider the view to be a JSP then there are no means a controller could actively set any values of UI components. (To me this is the core of the pattern: the controller actually updates the view actively by setting values of input / output UI components, not the other way round (view getting fields from a model object). This can't be done with the above techniques as a JSP has no means to be accessesd this way.
It could be implemented in a web environment based on Javascript though. Consider your view being the DOM and your controller being a Javascript component. The JS controller has direct write access to the DOM and therefore could update single fields actively like the pattern suggests. To update / get the model the JS controller could talk to a server-side system e. g. based on a REST API via Ajax.
A plain templating solution like JSP cannot be used to offload all logic to controller, at least in real world cases. I think this kind of thing can be achieved with JSF.
If you want to learn about how things are done I recommend you to take a look at Spring MVC. It's source code can teach you a lot.

Wicket 1.5 PageParameters are empty

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)
{
...
}

Categories

Resources