5

I have wicket's AutoCompleteTextField. To update the model I use 'onblur' event. And I need to refresh text field after 'onblur' event happens, because there is validation required.

Here is code sample to illustrate the issue

WebPage subclass:

public class TestPage extends WebPage {

    private Integer testField;

    public TestPage() {

        final List<Integer> allowedValues = new ArrayList<Integer>();
        for (int i = 0; i < 5; i++) {
            allowedValues.add(50 + i * 5);
        }

        final PropertyModel<Integer> testModel = new PropertyModel<Integer>(this, "testField");

        final AutoCompleteSettings autoCompleteSettings = new AutoCompleteSettings();
        autoCompleteSettings.setShowListOnEmptyInput(true);
        autoCompleteSettings.setShowListOnFocusGain(true);

        final AutoCompleteTextField<Integer> testInput =
                new AutoCompleteTextField<Integer>("testInput", testModel, autoCompleteSettings) {
                    @Override
                    protected Iterator<Integer> getChoices(final String input) {
                        return allowedValues.iterator();
                    }
                };

        testInput.setOutputMarkupId(true);
        testInput.setMarkupId("testInput");
        add(testInput);

        testInput.add(new AjaxFormComponentUpdatingBehavior("onblur") {
            @Override
            protected void onUpdate(final AjaxRequestTarget target) {
                target.add(testInput);
            }
        });
    }
} 

Corresponding HTML:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" xml:lang="en"
      lang="en">
<body>

<input type="text" wicket:id="testInput"/>

</body>
</html>

The problem is that it is impossible to select value by mouse click.

I've tried using OnChangeAjaxBehavior - and selection by mouse click works, but I don't want to perform validation after every single change (e.g. user wants to type 54, he types 5 => validation starts because OnChangeAjaxBehavior is fired)

I've tried using combination of both AjaxFormComponentUpdatingBehavior("onblur") and OnChangeAjaxBehavior and I had the same problem: can't select value by mouse click, because 'onblur' is fired before 'onchange'

Please note that if you comment the line target.add(testInput);, it will work as expected.

It seems to be similar to this Wicket issue

It says that issue is fixed for 6.18.0 version, but I use exactly Wicket 6.18.0 and still have this problem.

We've been performing upgrade from Wicket 1.4 to wicket 6. And in Wicket 1.4 it worked fine.

Please give me any advice on how to resolve this issue. Your help will be really appreciated. Thanks in advance.

ComeOn
  • 120
  • 8
  • There is probably a better way to do it, but you could set a flag in the `onblur`, and check for it in the `onchange`. – Rob Audenaerde Mar 24 '15 at 09:35
  • Thanks RobAu! I've already thought about it but it does not solve it: if user inputs 5 -> on change fired and I set flag and then he decides to select 50 or 55 by mouse -> so I have the same issue – ComeOn Mar 24 '15 at 09:39
  • I'm using just an `OnChangeAjaxBehavior` and it workd for me. The issue you mentioned affected me also and for me it was fixed. – Robert Niestroj Mar 24 '15 at 09:43
  • Thank you, Robert. I know that `OnChangeAjaxBehavior` will work, but it will not be nice for the user. Imagine the following: I have valid range 40-90. User inputs 5, so in `OnChangeAjaxBehavior` I validate it, show error message (5 is not in range) and because I update the field - cursor moved to the first first position in text field. You have to agree it will be quite annoying. – ComeOn Mar 24 '15 at 09:48
  • 1
    You could use a jquery script to place the cursor at the end of the text in the input after you update it. – papkass Mar 25 '15 at 12:17
  • Thank you, pikand. I ended up doing almost exactly you are suggesting. Instead on `OnchageAjaxBehavior` I use `AjaxFormComponentUpdatingBehavior('onchange')` which is not fired every time I input something. And during component refresh I set cursor to the last position in the input field. – ComeOn Mar 26 '15 at 14:43

1 Answers1

0

I suggest you to use wicket Jquery UI autocomplete box:

Html:

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<wicket:head>
    <title>Wicket - jQuery UI: auto-complete</title>
    <style type="text/css">
        .ui-autocomplete {
            max-height: 200px;
            overflow-y: auto;
            overflow-x: hidden;
            padding-right: 20px;
        }   
    </style>
</wicket:head>
</head>
<body>
<wicket:extend>
    <div id="wrapper-panel-frame" class="ui-corner-all">
        <form wicket:id="form">
            <div>Choose your favorite rock genre: (that starts with your criteria)</div>
            <br/>
            <input wicket:id="autocomplete" type="text" size="30" title="enter your criteria here"></input><br/>
            <br/>
            <div wicket:id="feedback" style="width: 360px;"></div>
        </form>
    </div>
</wicket:extend>
</body>
</html>

Java

package com.googlecode.wicket.jquery.ui.samples.pages.autocomplete;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;

import com.googlecode.wicket.jquery.ui.form.autocomplete.AutoCompleteTextField;
import com.googlecode.wicket.jquery.ui.panel.JQueryFeedbackPanel;

public class DefaultAutoCompletePage extends AbstractAutoCompletePage
{
    private static final long serialVersionUID = 1L;
    private static final List<String> CHOICES = Arrays.asList("Acid rock", "Alternative metal", "Alternative rock", "Anarcho punk", "Art punk", "Art rock", "Beat music", "Black metal", "Blues-rock", "Britpop", "Canterbury scene",
            "Chinese rock", "Christian metal", "Crossover Thrash Metal", "Crust punk", "Crustgrind", "Dark cabaret", "Death metal", "Deathcore", "Deathrock", "Desert rock", "Djent", "Doom metal", "Dream pop", "Drone metal",
            "Dunedin Sound", "Electronic rock", "Emo", "Experimental rock", "Folk metal", "Folk rock", "Freakbeat", "Funk metal", "Garage punk", "Garage rock", "Glam metal", "Glam rock", "Goregrind", "Gothic metal", "Gothic rock",
            "Grindcore", "Groove metal", "Grunge", "Hard rock", "Hardcore punk", "Heavy metal", "Indie pop", "Indie rock", "Industrial metal", "Industrial rock", "J-Rock", "Jazz-Rock", "Krautrock", "Math rock", "Mathcore",
            "Melodic Death Metal", "Melodic metalcore", "Metalcore", "Neo-psychedelia", "New Prog", "New Wave", "No Wave", "Noise pop", "Noise rock", "Noisegrind", "Nu metal", "Paisley Underground", "Pop punk", "Pop rock", "Pornogrind",
            "Post-Britpop", "Post-grunge", "Post-hardcore", "Post-metal", "Post-punk", "Post-punk revival", "Post-rock", "Power metal", "Power pop", "Progressive metal", "Progressive rock", "Psychedelic rock", "Psychobilly", "Punk rock",
            "Raga rock", "Rap metal", "Rap rock", "Rapcore", "Riot grrrl", "Rock and roll", "Rock en Español", "Rock in Opposition", "Sadcore", "Screamo", "Shoegazer", "Slowcore", "Sludge metal", "Soft rock", "Southern rock", "Space Rock",
            "Speed metal", "Stoner rock", "Sufi rock", "Surf rock", "Symphonic metal", "Technical Death Metal", "Thrash metal", "Thrashcore", "Twee Pop", "Unblack metal", "World Fusion");

    public DefaultAutoCompletePage()
    {
        // Form //
        final Form<Void> form = new Form<Void>("form");
        this.add(form);

        // FeedbackPanel //
        final FeedbackPanel feedback = new JQueryFeedbackPanel("feedback");
        form.add(feedback.setOutputMarkupId(true));

        // Auto-complete //
        form.add(new AutoCompleteTextField<String>("autocomplete", new Model<String>()) {

            private static final long serialVersionUID = 1L;

            @Override
            protected List<String> getChoices(String input)
            {
                List<String> choices = new ArrayList<String>();
                String inputLowerCase = input.toLowerCase();

                int count = 0;
                for (String choice : CHOICES)
                {
                    if (choice.toLowerCase().startsWith(inputLowerCase))
                    {
                        choices.add(choice);

                        // limits the number of results
                        if (++count == 20)
                        {
                            break;
                        }
                    }
                }

                return choices;

                //
                // Equivalent to:
                // return ListUtils.startsWith(input, CHOICES);
                //
            }

            @Override
            protected void onSelected(AjaxRequestTarget target)
            {
                info("Your favorite rock genre is: " + this.getModelObject());
                target.add(feedback);
            }
        });
    }
}

You can change this component whichever event you want

check this below link if that not suit:

http://www.7thweb.net/wicket-jquery-ui/autocomplete/DefaultAutoCompletePage;jsessionid=7916524E210E1245C95DCCB697DE6182?0

soorapadman
  • 4,451
  • 7
  • 35
  • 47