nerdlyist
nerdlyist

Reputation: 2857

Add behavior to Wicket Tab

I have a wicket application on a page we have various forms for the same model split into separate tabs. What I need to do is whenever a tab is clicked check to see if a js variable tabDirty is set to true or false. If it is true I would launch a confirm prompt if okay then reset that form and move to the clicked tab. If cancel stay on that tab with keeping current changes.

I have this js for the warning nothing fancy

function warnOnChange(){
    if(tabDirty){
        decision = confirm('Leave?');
        if(decision){
            resetTab(); //sets tabDirty back to false
        } else {
            return false;
        }
    }
}

I have a super simple wicket behavior

public class WarnChangePromptOnClickBehavior extends Behavior {

    @Override
    public void bind(Component component) {
        component.add(JQBehaviors.mouseClick(EditMerchant.WARN_ON_CHANGE));
    }
}

and that behavior is added to the AjaxFallBackLink

AjaxTabbedPanel<CustomAjaxTab> tabbedPanel = new AjaxTabbedPanel<CustomAjaxTab>("tabbedPanel", tabList, new Model<>(0)) {

    private static final long serialVersionUID = 1L;

    @Override
    protected WebMarkupContainer newLink(final String linkId, final int index) {
        AjaxFallbackLink<Void> link = new AjaxFallbackLink<Void>(linkId) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(final AjaxRequestTarget target) {
                TabbedPanel<CustomAjaxTab> selectedTab = setSelectedTab(index);
                CustomAjaxTab tab = tabList.get(index);
                if (target != null) {

                    tab.getPanel(linkId);

                    target.add(selectedTab);
                }
                onAjaxUpdate(target);
            }
        };

        link.add(new WarnChangePromptOnClickBehavior());
        return link;
    }

};  

Current behavior with this is that if there is no change the tabs switch no prompt. If there is a change then I get the prompt. If okay tabDirty is reset and go to the next page clearing changes. Issue is that if I click cancel I still navigate to the next tab and lose changes. I know there is something in onClick I need to change but it is just not registering with me.

Upvotes: 0

Views: 747

Answers (2)

nerdlyist
nerdlyist

Reputation: 2857

Not sure if this is the appropriate way to do this but I solved my issue like this:

Same old js just slightly modified to return what the user chose:

function warnOnChange(){
    decision = true;
    if(tabDirty){
        decision = confirm('Leave?');
        if(decision){
            resetTab();
        }
    }
    return decision;
}

Dumped the whole behavior code although I still think it could be used just not sure at the moment...

So to make this all work on the link I override the updateAjaxAttributesof the link with a precondition:

AjaxTabbedPanel<CustomAjaxTab> tabbedPanel = new AjaxTabbedPanel<CustomAjaxTab>("tabbedPanel", tabList, new Model<>(0)) {

private static final long serialVersionUID = 1L;

@Override
protected WebMarkupContainer newLink(final String linkId, final int index) {
    AjaxFallbackLink<Void> link = new AjaxFallbackLink<Void>(linkId) {

        private static final long serialVersionUID = 1L;

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

            AjaxCallListener ajaxCallListener = new AjaxCallListener();
            //very important to use the "return" if not then nothing happens with the response
            ajaxCallListener.onPrecondition("return " + WARN_ON_CHANGE);

            attributes.getAjaxCallListeners().add( ajaxCallListener );
        }

        @Override
        public void onClick(final AjaxRequestTarget target) {
            TabbedPanel<CustomAjaxTab> selectedTab = setSelectedTab(index);
            CustomAjaxTab tab = tabList.get(index);
            if (target != null) {

                tab.getPanel(linkId);

                target.add(selectedTab);
            }
            onAjaxUpdate(target);
        }
    };

    link.add(new WarnChangePromptOnClickBehavior());
    return link;
}
};

Upvotes: 0

martin-g
martin-g

Reputation: 17533

It is not that easy to intercept the JS event loop, especially when using Ajax requests.

Here is an approach that may do the job:

  1. In warnOnChange() if dirty then call event.preventDefault() and event.stopImmediatePropagation(). This will tell the browser to not follow the link / make an Ajax call. Then show the confirmation dialog as you do now.
  2. If the user presses Cancel then there is nothing more to do
  3. If the use confirms then set dirty to false and do jQuery(event.target).triggerHandler(event.type), i.e. execute the same event (click) on the link. This time it won't be dirty and it will proceed with the Ajax call.

Upvotes: 1

Related Questions