Wicket get button component text - wicket

I would like to get the text of a button submitProceed and will use it in my code/logic.
HTML
<button wicket:id="submitProceed" type="button" class="btn btn-sm btn-primary btn-save" disabled="disabled">Submit</button>
Is it possible to get the button text Submit? Also, how to I change this to Proceed?
This is how I initialize my button component:
private Component m_btnSubmit;
...
private Component createForm() {
Form<Void> result = new Form<>("form");
...
result.add(m_btnSubmit = createSubmit("submit"));
...
return result;
}
private Component createSubmit(String wicketId) {
AjaxButton result = new AjaxButton(wicketId) {
private static final long serialVersionUID = 1L;
#Override
protected void onConfigure() {
super.onConfigure();
...
setOutputMarkupId(true);
}
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
...
}
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
super.onSubmit(target, form);
// TODO: Get button text here
// Check button text if either `Submit` or `Proceed`
// Action depending on button text (Also change button text)
}
#Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
super.onError(target, form);
...
}
};
...
return result;
}
Solution:
First of All, I would like to thank #Andrea and #martin for their solution, I just tweak it a bit for fit my existing code.
Since I need a span containing the text Submit and later be changed to Proceed... I need to add a span inside button tag like this:
<button wicket:id="submit" type="button"><span wicket:id="labelSubmit">Submit</span&lg;</button>
the problem with this, I am getting an error that seems it would not allow button to have a nested component.
Error is something like this:
org.apache.wicket.markup.MarkupException: Expected close tag for '<button wicket:id="submit" type="button">' Possible attempt to embed component(s) '<span wicket:id="labelSubmit">' in the body of this component which discards its body.
To fix this, I need to change from button to a so it would look like this:
<a wicket:id="submit" type="submit"><span wicket:id="labelSubmit">Submit</span&lg;</a>
...
IModel m_labelModel = Model.of("Submit");
Label m_labelSubmit = new Label("labelSubmit", m_labelModel);
m_labelSubmit.setOutputMarkupId(true);
...
In my button's onSubmit:
m_labelModel.setObject("Proceed");
target.add(this);
Note that I only did change m_labelModel, but I need to add the current button (this) so that the change will reflect in the UI.
For those, having the same issue or setup... hope this helps :)

If you use new AjaxButton(String, IModel) constructor, as Andrea Del Bene suggested, then the model will be used to set the value attribute of the button:
<button value="Submit"></button>
If you need to manipulate the textContent of the <button>, i.e. <button>!!!THIS!!!</button> then you can add a Label component as a child:
IModel<String> labelModel = Model.of("Submit");
Label label = new Label("labelId", labelModel);
label.setOutputMarkupId(true);
button.add(label);
...
In AjaxButton#onSubmit(AjaxRequestTarget target) you can update it:
labelModel.setObject("New value");
target.add(label);

you should use button's constructor that takes also a model as button's label:
IModel labelModel = Model.of("Submit");
new Button<>("submit", labelModel);
Than you can use the model to get/set this value

Related

Swap the type of link depending on model object

I'm at complete loss how to proceed further:
I have panel with a DropDownChoice and a submit button next to it. Depending on the selected value of the DropDownChoice (Obtained upon the firing of a OnChangeAjaxBehavior attached to it, the submit button needs to either replace the whole panel with a different one, OR become an ExternalLink.
Currently, the code looks like that:
public class ReportSelectionPanel extends Panel {
protected OptionItem selectedOption ;
public ReportSelectionPanel(String id) {
super(id);
IModel<List<OptionItem>> choices = new AbstractReadOnlyModel() {
// Create a list of options to be displayed in the DropDownChoice
} ;
final IModel<OptionItem> optionModel =
new PropertyModel<OptionItem>(this,"selectedOption") ;
final DropDownChoice<OptionItem> options =
new DropDownChoice("selectChoice",optionModel,choices) ;
// I don't know what the button should be... Plain Button? A Link?
final Component button = ???
options.add( new OnChangeAjaxBehavior() {
protected void onUpdate(AjaxRequestTarget target) {
if ( selectedOption.getChild() == null ) {
// button becomes an ExternalLink.
// A new window will popup once button is clicked
} else {
// button becomes a Something, and upon clicking,
// this ReportSelectionPanel instance gets replaced by
// an new Panel instance, the type of which is
// selectedOption.getChild()
}
} ) ;
I'm really not quite sure what the commented lines should become to achieve the result. Any suggestions?
Thanks!
Eric
IMHO it's nicer to keep just one button and just react differently depending on the selected option:
final Component button = new AjaxButton("button") {
public void onClick(AjaxRequestTarget target) {
if (selectedOption.getChild() == null) {
PopupSettings popup = new PopupSettings();
popup.setTarget("'" + externalUrl + "'");
target.appendJavascript(popup.getPopupJavaScript());
} else {
ReportSelectionPanel.this.replaceWith(new ReportResultPanel("..."));
}
}
};
// not needed if options and button are inside a form
// options.add( new OnChangeAjaxBehavior() { } ) ;

Wicket - changing panels through a dropdown

I have a dropdown component added on a page. the purpose of this dropdown is to change the type of input form that is rendered. for example, different forms have different required fields, editable fields, etc.
public final class Test extends WebPage
{
CustomPanel currentPanel = new MeRequest("repeater",FormType.MIN);
public Test(PageParameters parameters)
{
add(currentPanel);
DropDownChoice ddc = new DropDownChoice("panel", new PropertyModel(this, "selected"), panels, choiceRenderer);
ddc.add(new AjaxFormComponentUpdatingBehavior("onchange") {
protected void onUpdate(AjaxRequestTarget target) {
System.out.println("changed");
currentPanel = new MeRequest("repeater",FormType.PRO);
target.add(currentPanel);
}
});
add(ddc);
}
i've tried various options with limited results. the only real success has been updating the model, but what i really want to do is change how the components behave.
any thoughts on what i'm missing?
1) If you want to replace one panel with another you may just do the following.
First of all, you should output the markup id of the original panel:
currentPanel.setOutputMarkupId(true);
And then in the ajax event handler write something like that:
protected void onUpdate(AjaxRequestTarget target) {
CustomPanel newPanel = new MeRequest("repeater", FormType.PRO);
currentPanel.replaceWith(newPanel);
currentPanel = newPanel;
currentPanel.setOutputMarkupId(true);
target.addComponent(currentPanel);
}
In this case with every change of dropdown choice you add new panel to the page and you remove old panel from the page.
2) But I would proposed a slightly different approach to your problem. You should move the construction logic of your panel to the onBeforeRender() method:
public class MeRequest extends Panel {
private FormType formType;
public MeRequest(String id, FormType formType) {
super(id);
this.formType = formType;
// don't forget to output the markup id of the panel
setOutputMarkupId(true);
// constructor without construction logic
}
protected void onBeforeRender() {
// create form and form components based on value of form type
switch (formType) {
case MIN:
// ...
break;
case PRO:
// ...
break;
}
// add form and form components to panel
addOrReplace(form);
form.add(field1);
form.add(field2);
// ...
super.onBeforeRender();
}
public void setFormType(FormType formType) {
this.formType = formType;
}
}
Then you'll be able to only change type of the panel in the ajax event:
protected void onUpdate(AjaxRequestTarget target) {
currentPanel.setFormType(FormType.PRO);
target.addComponent(currentPanel);
}
Thus we rebuilt the original panel without recreating it.

How to programmatically open a gwt listbox?

I have a user form with a lot of gwt listbox. The form is like an excel form with named list.
It's ugly and the arrows take place.
I would like the cells were like in excel. The arrow appears only when you click in the cell.
I start to program my own widget with a textbox and a listbox embedded into a DeckPanel, switching when you click on the textbox or when the value change. But with this solution, it is necessary to click again to open the listbox.
Now, it will be great, if when you click on the textbox, the listbox will be displayed already open.
In the code below, I try to do this into the method onClick wih this line:
DomEvent.fireNativeEvent(event.getNativeEvent(), listBox);
But it has no effects.
public class CustomListBox extends Composite implements ClickHandler,
ChangeHandler, HasChangeHandlers {
private final StringListBox listBox;
private final TextBox textBox;
private final DeckPanel panel;
public CustomListBox() {
textBox = new TextBox();
textBox.addClickHandler(this);
textBox.setReadOnly(true);
listBox = new StringListBox();
listBox.addChangeHandler(this);
panel = new DeckPanel();
panel.add(textBox);
panel.add(listBox);
panel.showWidget(0);
// All composites must call initWidget() in their constructors.
initWidget(panel);
}
#Override
public void onClick(ClickEvent event) {
Object sender = event.getSource();
if (sender == textBox) {
panel.showWidget(1);
DomEvent.fireNativeEvent(event.getNativeEvent(), listBox);
}
}
public void addItem(String item) {
listBox.addItem(item);
}
public int getSelectedIndex() {
return listBox.getSelectedIndex();
}
public String getItemText(int selectedIndex) {
return listBox.getItemText(selectedIndex);
}
#Override
public HandlerRegistration addChangeHandler(ChangeHandler handler) {
return listBox.addChangeHandler(handler);
}
#Override
public void onChange(ChangeEvent event) {
Object sender = event.getSource();
if (sender == listBox) {
textBox.setText(getItemText(getSelectedIndex()));
panel.showWidget(0);
}
}
}
Since you are already programming your own widget, why don't you go all the way. Don't swap out the text box for a list box widget. Instead of a textbox use a label. Add an arrow to your label background when you mouse over, then use a popupPanel for the list itself. In the popupPanel you can make the list items whatever you like, just make sure when you click on it, it sets the text in your original label.

Gwt form question

I have a gwt form which has about 70-100 widgets (textboxes,listboxes,custom widgets etc)
I am trying to implement the features of CUT ,COPY in this form .For this i have 2 buttons right on top of the form.
Now the problem i have is that when i click on the copy button , the widget that was focused in the form looses focus and i dont know which text to copy(or which widget was last focused before the focus getting to the copy button)
I was planning to implement blur handlers on all the widgets but i feel is a very laborious and not a good solution.
How can i get around this issue?
Thanks
Perhaps someone with a deeper insight might provide a better approach but I beleive adding blur handlers is perfectly valid. I do not quite see why you think it would be laborious, after all you don't need a different handler for each of your widgets, you can get away with only one(at most a couple for a variety of controls..), here is a very simple example,
public class CustomBlurHandler implements BlurHandler{
Object lastSource;
String text;
#Override
public void onBlur(BlurEvent event) {
if (event.getSource() instanceof TextBox) {
lastSource = event.getSource();
text = textBox.getSelectedText();
}
}
public Object getLastSource() {
return lastSource;
}
public String getText() {
return text;
}
}
and onModuleLoad :
public class Test implements EntryPoint {
CustomBlurHandler handler = new CustomBlurHandler();
public void onModuleLoad() {
TextBox text1 = new TextBox();
TextBox text2 = new TextBox();
text1.addBlurHandler(handler);
text2.addBlurHandler(handler);
Button b = new Button("Get last selected text");
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert(handler.getLastSource()+ " " + handler.getText());
}
});
RootPanel.get().add(text1);
RootPanel.get().add(text2);
RootPanel.get().add(b);
}
}

wicket issue unable to move items from one listmultiplechoice another

I have a Wicket Panel. It has two text fields adjacent to each other and two ListMultipleChoice controls adjacent to each other and two buttons "add and remove" in between two these ListMultipleChoice's.
I was unable to move the items from one list box to another unless I entered some values in text fields, which were prior to the list boxes.
If values were entered in text fields, I was able to move the items.
Please find the code below.
TextField<BigDecimal> textfield1 = new TextField<BigDecimal>("value1")
{
private static final long serialVersionUID = 8199976201679629866L;
#Override
public IConverter getConverter(Class<?> type) {
return new FixedDecimalPlacesConverter();
}
};
textfield1.setType(BigDecimal.class);
textfield1.setLabel(new Model<String>("Value1"));
textfield1.setRequired(true)
.add(PositiveNumberValidator.getInstance())
.add(new FixedDecimalPlacesValidator(2));
add(new FeedBackBorder("Border1").add(textfield1));
TextField <BigDecimal> textfield2 = new TextField<BigDecimal>("value2")
{
private static final long serialVersionUID = 8199976201679629866L;
#Override
public IConverter getConverter(Class<?> type) {
return new FixedDecimalPlacesConverter();
}
};
textfield2.setType(BigDecimal.class);
textfield2.setOutputMarkupId(true);
textfield2.setLabel(new Model<String>("Value2"));
textfield2.setRequired(true)
.add(PositiveNumberValidator.getInstance())
.add(new FixedDecimalPlacesValidator(2));
add (new FeedBackBorder("Border2").add(textfield2));
ChoiceRenderer<UserBean> choiceRenderer = new ChoiceRenderer<UserBean>("userName", "userID.ID");
availableUsers= new ListMultipleChoice<UserBean>( "availableUsersBean", availableUsersList, choiceRenderer );
availableUsers.setOutputMarkupId(true);
availableUsers.setLabel(new Model<String>("Available Users"));
add(new FeedBackBorder("availableUsersBorder").add(availableUsers));
selectedUsers = new ListMultipleChoice<UserBean>( "selectedUsersBean", selectedUsersList, choiceRenderer );
selectedUsers.setOutputMarkupId(true);
selectedUsers.setLabel(new Model<String>("Selected Users"));
add(new FeedBackBorder("selectedUsers Border").add(selectedUsers ));
add = new AjaxButton("add") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
update(target, availableUsers.getModelValue(),availableUsers, selectedUsers);
}
};
add(new FeedBackBorder("addBorder").add(add));
remove = new AjaxButton("remove") {
#Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
update(target, selectedUsers.getModelValue(), selectedUsers , availableUsers);
}
};
add(new FeedBackBorder("removeBorder").add(remove));
What could be the issue?
add.setDefaultFormProcessing(false);
remove.setDefaultFormProcessing(false);
I am using org.apache.wicket.markup.html.form.Button which allows you to turn off full form submit with button click with the setDefaultFormProcessing(boolean). This should allow you to process actions without submitting your complete form, therefore not validating required textfields.
At a first glance: Your TextFields are required. Submitting the Form via AjaxButtons wouldn't trigger the onSubmit method for an invalid form but the onError method.
Possible Solutions (in no particular order):
Moving the Lists to a nested form
Moving the contents of the onSubmit to a separate method and call it from onError too
Move the item moving logic to a pure JavaScript based Behaviour or Decorator that doesn't trigger a form submit.