It's common to want the user to confirm his action if it would be hard to reverse, e.g. if he asked to delete something. The confirmation can be easily obtained via a javascript confirm dialog box. If you'd rather not use javascript, another approach is outlined below.

Using Javascript

Wicket 6.x

This is a solution from Sven Meier - 'overwrite #updateAjaxAttributes in your behavior or AjaxLink'. To make a reusable Component, simply create an abstract base class:

public abstract class ConfirmationLink<T> extends AjaxLink<T>
{
	private static final long serialVersionUID = 1L;
	private final String text;

	public ConfirmationLink( String id, String text )
	{
		super( id );
		this.text = text;
	}

	@Override
	protected void updateAjaxAttributes( AjaxRequestAttributes attributes )
	{
		super.updateAjaxAttributes( attributes );

		AjaxCallListener ajaxCallListener = new AjaxCallListener();
		ajaxCallListener.onPrecondition( "return confirm('" + text + "');" );
		attributes.getAjaxCallListeners().add( ajaxCallListener );
	}
}

Earlier Wicket versions

Here's one way to do get confirmation, using Javascript:

Link removeLink = new Link("removeLink") {
			@Override
			public void onClick() {
				// do something you want to confirm beforehand
			}
		};

removeLink.add( new SimpleAttributeModifier("onclick", "return confirm('are you sure?');"));

SimpleAttributeModifier will replace any existing onclick handler in the html. We can instead add our javascript to any existing javascript by creating our own AttributeModifier instead of using SimpleAttributeModifier:

public class JavascriptEventConfirmation extends AttributeModifier {
	public JavascriptEventConfirmation(String event, String msg) {
		super(event, new Model(msg));
	}

	protected String newValue(final String currentValue, final String replacementValue) {
		String prefix = "var conf = confirm('" + replacementValue + "'); " +
			"if (!conf) return false; ";
		String result = prefix;
		if (currentValue != null) {
			result = prefix + currentValue;
		}
		return result;
	}
}

Then we attach the modifier to the link:

	removeLink.add(new JavascriptEventConfirmation("onclick", "are you sure?"));

If you are using the same confirmation in more than one link, you should subclass Link to encapsulate the change:

abstract public class ConfirmLink extends Link {
      public ConfirmLink(String id, String msg) {
           super(id);
           add(new JavascriptEventConfirmation("onclick", "are you sure?"));
      }

      @Override
      abstract public void onClick();

}

(The subclass could of course use SimpleAttributeModifier instead.)

Without Javascript

If you don't want to use javascript, you could bring up a separate web page with a confirmation form in it. But it's possible to display the confirmation request on the form page itself. The idea (due to Ed Eustace) is to use the wicket Component.replaceWith() method to replace some panel on the page with a confirmation panel.

First, here's the confirmation panel:

public abstract class ConfirmDeletePanel extends Panel {
     public ConfirmDeletePanel(String id, String message) {
         super(id);
	 add(new Label("message", message));
	 add(new Link("confirm") {
	      @Override
	      public void onClick() {
	        onConfirm();
	      }
	    });
	 add(new Link("cancel") {
	      @Override
	      public void onClick() {
	        onCancel();
	      }
	    });
     }
     protected abstract void onCancel();
     protected abstract void onConfirm();
}

(The corresponding html should be pretty obvious.)

Now assume the link to be confirmed is inside a panel called MyPanel. The link has a onClick method that does the panel replacement:

Link removeLink = new Link("removeLink") {
	@Override
	public void onClick() {
		MyPanel.this.replaceWith(new ConfirmDeletePanel(
				MyPanel.this.getId(), "are you sure") {

			@Override
			protected void onCancel() {
				this.replaceWith(MyPanel.this);
			}

			@Override
			protected void onConfirm() {
				// do something you want confirmed beforehand
				// .... then
				this.replaceWith(MyPanel.this);
			}
		});
	}

};
  • No labels

5 Comments

  1. make it a custom component like this:

     public class ConfirmLink extends Link {   public ConfirmLink(String id, String msg) {     super(id);
         add(new SimpleAttributeModifier("onclick", "return confirm('" + msg + "');"));
       } }  new ConfirmLink("removeLink", "are you sure?") {  public void onClick() {    ..  }}; 
    
  2. the above use of SimpleAttributeModifier is not appropriate because it overwrites the value, a much better approach would be to insert the confirmation script as the first part of the onclick event ala

     class JavascriptEventConfirmation extends AbstractBehavior {     private final String msg;     private final String event;       public JavascriptEventConfirmation(Striong event, String msg) {           this.msg=msg;            this.event=event;       }      protected void onComponentTag(ComponentTag tag) {         String script=tag.getAttributes().get(event);         script="if (!confirm('"+msg+"')) return false; "+script;         tag.put(event, onclick);     }}
    

    now you have a reusable behavior that can be attached to links, forms, etc.

    to improve make msg an IModel

    1. It was just an example smart ass (smile). But if you want to create a reusable behavior, even nicer would be:

      public class JavascriptEventConfirmation extends AttributeModifier {
      
        public JavascriptEventConfirmation(String event, String msg) {
          super(event, true, new Model(msg));
        }
      
        protected String newValue(final String currentValue, final String replacementValue) {
          return replacementvalue + ";" + currentValue;
        }
      }
      

      or something in that fashion.

  3. I think discussing the more reusable approach is reasonable. I'll change it to use AttributeModifier instead of AbstractBehavior later.

    I intended all along to show the replaceWith trick. But right now my example I copied from the blog entry and modified isn't working and I need to figure out why.