Wicket - AjaxEventBehavior not rendered properly - java

Look at the following snippet.
add(new AjaxEventBehavior("onclick") {
private boolean toggle = false;
#Override
protected void onEvent(AjaxRequestTarget target)
{
log.debug("onEvent: " + toggle);
if (toggle)
{
toggle = false;
target.prependJavaScript("toogle(true)");
}
else
{
toggle = true;
target.prependJavaScript("toogle(false)");
}
}
});
But after the page rendering [no errors, warnings], I could see no event associated to the DOM [verified by means of firebug]. Even the debug log was never printed.
Is there any option in wicket to verify the behavior is added or not?

You should iterate trougth Behaviors added to this component to verify your one is added:
for (Behavior behavior : component.getBehaviors()) {
if(AjaxEventBehavior.class.equals(behavior.getClass())) {
// it works
}
}

The behavior won't contribute its JavaScript if the component it is attached on is either invisible or disabled.
BTW both of your prependJavaScript() calls use the same content toggle(true).

You should (almost) never have HTML ids in your markup:
For Wicket these ids take precedence over generated unique markup ids. If the id is present multiple times on the page (e.g. if you use a component multiple times), all Ajax handlers will attach to the first markup tag with that id.

Related

GXT - send forms on enter, project-wide

I have an application which uses GXT and contains ±30 forms. I would like to make these forms so that when the user hits enter in a text field, the form gets submitted, like a regular browser form would.
I know I can add a key press listener to every text field, which would invoke the submit after enter is pressed, but since I want to apply this to every field in every form I am not sure if this is ideal.
Is there a simpler way to implement this in the entire application?
If not, which pattern should I use to add this functionality to every field? I can extend the TextField class, add the functionality in the child class and use the child class in the application. Or I can create a factory for the text field class which would also add the listener to the field. Or is there some other way, Decorator perhaps? I was wondering which of these approaches, if any, is generally preferred.
I would try something like this:
Event.addNativePreviewHandler(new NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
if (event.getNativeEvent().getEventTarget() != null) {
Element as = Element.as(event.getNativeEvent().getEventTarget());
if (as.getTagName().toLowerCase().equals("input") ||
as.getTagName().toLowerCase().equals("textarea")) {
// TODO submit data;
}
}
}
}
});
Every time someone hits the Enter Key and the cursor is placed on a input- or textarea-tag, you will get the control and can submit your data.
I don't think there is a way to do what you're asking directly in the GXT library. I do want to stress that extending the TextField class just to add an event handler to it is not the correct way to handle this. Event handlers are based on the composition of a class. It would be like extending a class with a List field just to add another element into the list.
A singleton factory class that created and initialises the Textfield for you would be the cleanest solution, in my opinion. It would allow you to effectively change defaults and add other handlers as required at a later time in a single place if requirements change.
You can try it with GWT JSNI also.
Steps to follow:
define a function in JavaScript that is called on Enter key press
call GWT JSNI from above JavaScript function that is exported at the time of onModuleLoad using GWT JSNI
get the Element from where this event is triggered and finally submit the form based on its tag name or Id
Sample code:
HTML/JSP:
<script>
window.onkeydown = keydown;
function keydown(event) {
if (event.which == 13) {
formSubmit(event.target);
}
}
</script>
JAVA(Entry Point):
import com.google.gwt.dom.client.Element;
public void onModuleLoad() {
exportFormSubmit();
...
}
public static void formSubmit(Element element) {
Window.alert("element tag name:" + element.getTagName() + "form ID:"
+ element.getParentElement().getId());
}
public static native void exportFormSubmit() /*-{
$wnd.formSubmit = $entry(#com.x.y.z.client.GWTTestProject::formSubmit(Lcom/google/gwt/dom/client/Element;));
}-*/;

Showing disabled SectionItems expanded in SmartGWT

When you disable a DynamicForm in SmartGWT, all the items in the form become disabled and thus unresponsive. This is expected and correct behaviour.
The problem is that if there are collapsed SectionItems in the form, they cannot be expanded before the form is re-enabled. Is there an easy way to make the sections interactive when a form is disabled?
SectionItem are FormItem whose drawing is handled by the containig DynamicForm.
Check http://forums.smartclient.com/showthread.php?t=15008.
Following options exist in achieving the required behavior.
These options do not disable the entire canvas of the form.
Option 1:
Use following method in place of form.setDisabled(true|false) as setFormDisabled(form, true|false);.
private void setFormDisabled(DynamicForm form, boolean isDisabled) {
FormItem[] fields = form.getFields();
for (FormItem field : fields) {
if (!(field instanceof SectionItem)) {
field.setDisabled(isDisabled);
}
}
}
Option 2:
Override form.*Disabled() methods and use as form.setDisabled(true|false).
DynamicForm form = new DynamicForm() {
private boolean isDisabled;
#Override
public boolean getDisabled() {
return isDisabled;
}
#Override
public void setDisabled(boolean disabled) {
this.isDisabled = disabled;
setFormDisabled(this, disabled);
}
};
This can be enhanced with Generics if multiple types of items need to be kept enabled in different forms.

GWT - how to get the tabText of selected tab?

I want to get the tab text when I click on a tab. I do this:
tabPanel.addSelectionHandler(new SelectionHandler<Integer>() {
#Override
public void onSelection(SelectionEvent<Integer> event) {
//get the tabtext here
}
});
But I only get the index.
Assuming you are using TabPanel and you haven't provided a custom Widget for the TabBar, you could do this:
tabPanel.addSelectionHandler(new SelectionHandler<Integer>() {
#Override
public void onSelection(SelectionEvent<Integer> event) {
String tabHtml = tabPanel.getTabBar().getTabHTML(event.getSelectedItem());
}
});
Of course, you will get the underlying HTML of the tab, that generally is a <div>tab text</div>. The text you put in the add() methods are wrapped in either a Label, or an HTML widget, whether you have chosen to display the tab text as HTML.
Of course this is not handy, generally you need to store somewhere the tab text (in a TabPanel extension I'd guess, or a model) at insertion time (overriding the add(...)s) and retrieve it when needed (by adding a simple getter for them).
You can get the selected tab by following.
tabPanel.getElement().getTitle();

GWT equivalent of jQuery change() for form elements

Can anyone tell me whether there is an equivalent method in GWT like change in jQuery for form elements like radio-buttons, checkboxes, etc, which is fired the moment any such button is checked or unchecked? If so, how do I use it? I found a method like addValueChangeHandler in the Google docs, but apart from providing the prototype, there is no working example.
Specifically, if I want a handler which will wait for a checkbox being checked or unchecked, and accordingly pop up an alert like A checkbox has been checked!!, along with that buttons accompanying text.
CheckBox newOption = new CheckBox();
newOption.setText("Check to see alert");
newOption.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
#Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
if (event.getValue()) {
Window.alert("Checkbox is checked!");
} else {
Window.alert("Checkbox is unchecked!");
}
}
});

Set focus on a component with Apache Wicket?

How do you set focus on a component with Apache Wicket? Searching leads to very little information, mostly on setting the default field. I do not want to set a default field, rather I am looking to set focus when, for example, a specific radio button is selected.
I suggest using the native org.apache.wicket.ajax.AjaxRequestTarget#focusComponent(). For example:
/**
* Sets the focus in the browser to the given component. The markup id must be set. If
* the component is null the focus will not be set to any component.
*
* #param component
* The component to get the focus or null.
*/
org.apache.wicket.ajax.AjaxRequestTarget#focusComponent(Component component)
Once you create your behavior to set the focus, you should be able to add it to the component on any event, just make sure that component is part of the AjaxRequestTarget. I don't see why this wouldn't work...
myRadioButton.add(new AjaxEventBehavior("onchange") {
#Override
protected void onEvent(AjaxRequestTarget target) {
myOtherComponent.add(new DefaultFocusBehavior());
target.addComponent(myForm);
}
});
Here's a link that shows how to create the default focus behavior if you do not have one already:
http://javathoughts.capesugarbird.com/2009/01/wicket-and-default-focus-behavior.html
If you only want to setFocus through javascript and don't want to reload a form or a component, you can use the following code:
import org.apache.wicket.Component;
public class JavascriptUtils {
private JavascriptUtils() {
}
public static String getFocusScript(Component component) {
return "document.getElementById('" + component.getMarkupId() + "').focus();";
}
}
And then in any Ajax Method you can use:
target.appendJavascript(JavascriptUtils.getFocusScript(componentToFocus));
For a pop-up like modalWindow my workaround solution was to use the attribute "autofocus" on the first input tag.
An easy solution is to add it to the html directly.
<input ..... autofocus>
Another solution is to add it to the modalWindow itself:
#Override
public void show(AjaxRequestTarget target) {
super.show(target);
setUpFocus();
}
protected void setUpFocus() {
DeepChildFirstVisitor visitor = new DeepChildFirstVisitor() {
#Override
public void component(Component component, IVisit<Void> iVisit) {
if (isAutofocusable(component)) {
component.add(new AttributeAppender("autofocus", ""));
iVisit.stop();
}
}
#Override
public boolean preCheck(Component component) {
return false;
}
};
this.visitChildren(FormComponent.class, visitor);
}
protected boolean isAutofocusable(Component component) {
if (component instanceof TextArea ||
component instanceof DropDownChoice ||
// component instanceof RadioChoice ||
component instanceof AjaxCheckBox ||
component instanceof AjaxButton ||
component instanceof TextField) {
return true;
}
return false;
}
RadioChoice is commented out because this solution is not working on that. For RadioChoice i would recommend to implement a FocusedRadioChoice:
public class FocusedRadioChoice<T> extends RadioChoice<T> {
//constructors...
#Override
protected IValueMap getAdditionalAttributes(int index, T choice) {
super.getAdditionalAttributes(0, choice);
AttributeMap am = new AttributeMap();
am.put("autofocus", "");
return am;
}
}
Is there a way to achieve the same without JavaScript?
(I am implementing a form with a feedback-Panel that only comes up when Javascript is turned off, so it would not make sense to depend on JavaScript there...,-)
I could only find answers which use JS .focs()... maybe Wicket 1.5 will provide a method Component.setFocus()...
If you happen to be using an Ajax button, you can simply call target.focusComponent(myComponent); in the button's onSubmit method.
#martin-g 's solution was the only solution that got it working for my scenario - a modal/pop up.
Note:
I think autofocus embedded explicitly in HTML only works on page load, not modal load so any efforts to skillfully set the autofocus attribute in the HTML of a modal just fail miserably - always.
Here I lay out the steps for setting the focus on an input field called 'myInput' using the full power of Wicket (no JS!):
In onInitialize:
// Make sure the field has an ID in markup
myInput.setOutoutMarkupId(true);
Provide an overridden show method where you call the focusComponent method:
public void show(AjaxRequestTarget target)
{
// Make sure you call the super method first!
super.show(target);
target.focusComponent(myInput);
}
This does require that your component is an attribute of your modal content class so that you can access it in the show method. To avoid creating a class attribute for your input component you could blend this solution with the solution from BlondCode by replacing that solution's
component.add(new AttributeAppender("autofocus", ""));
with
target.focusComponent(component);
This also works!

Categories