Search code examples
javaajaxtextareawicketwicket-6

how to update a wicket AjaxEditableMultiLineLabel model on an ajax call


I have tried multiple things with no success. At the moment my code looks like this:

HomePage.html:

            <div wicket:id="text3" contenteditable="true">
            </div>

HomePage.java:

    public HomePage(final PageParameters parameters) {
//...

    AjaxEditableMultiLineLabel textArea = 
            new AjaxEditableMultiLineLabel ("text3", new PropertyModel (this, "text3") );


    textArea.add(new AjaxEventBehavior ("keyup") {

        @Override
        protected void onEvent(AjaxRequestTarget target) {
            System.out.println( "on event!" );
            System.out.println( getText3 () );
        }
    });
//...
}

/**
 * @return gets text3
 */
public String getText3() {
    return text3;
}

/**
 * @param text3
 *            the text3 to set
 */
public void setText3(String text3) {
    this.text3 = text3;
}

I want to get the content inside the "div" but it's not being updated on the ajax call. Can I force it to send it somehow?

By the way, what I'm trying to achieve is getting the plain text content of a rich text area every time this is updated, in case there is a simpler way of doing it in wicket.


Solution

  • You add an AjaxEventBehavior to a AjaxEditableMultiLineLabel that is NOT CORRECT. The AjaxEditableMultiLineLabel is a Panel that contains two components:

    • Label
    • Editor (textarea)

    Any of Ajax behavior has to be add to any of these components. In your case you have to add a behavoir to the editor.

    (following full working example is on https://repo.twinstone.org/projects/WISTF/repos/wicket-examples-6.x/browse )

    The markup

        <h2>Form</h2>
        <form wicket:id="form">
            <div wicket:id="text"></div>
            <input wicket:id="submit" type="submit" value="Send" />
        </form>
    
        <hr/>
    
        <h2>Result</h2>
        <div wicket:id="result">[result placeholder]</div>
    

    The code snippet

        final IModel<String> textModel = Model.of("initial text");
    
        Form<String> form = new Form<>("form", textModel);
        add(form);
    
        AjaxEditableMultiLineLabel<String> textArea = new AjaxEditableMultiLineLabel<String>(
                "text", textModel) {
    
            private static final long serialVersionUID = 1L;
    
            @Override
            protected FormComponent<String> newEditor(MarkupContainer parent,
                    String componentId, IModel<String> model) {
                final FormComponent<String> editor = super.newEditor(parent,
                        componentId, model);
    
                editor.add(new AjaxFormComponentUpdatingBehavior("keyup") {
    
                    private static final long serialVersionUID = 1L;
    
                    @Override
                    protected void onUpdate(AjaxRequestTarget target) {
                        System.out.println("Ajax update for textArea " + editor.getDefaultModelObjectAsString());
    
                    }
                });
    
                return editor;
            }
    
        };
    
        textArea.setCols(50);
        textArea.setRows(20);
    
        form.add(textArea);
        form.add(new SubmitLink("submit"));
    
        add(new Label("result", textModel));
    

    WARNING: PREVIOUS CODE IS REALLY VERY SLOW

    The code is very slow, becuase each keypress/release makes following:

    1. Call the server with the content of textarea
    2. Invoke code on the server side (update, render, etc.)
    3. Send back the whole result tag as html in an XML response (AJAX)
    4. Replace the whole result tag

    It is slow on localhost, in a real internet is definitely not usable.

    SOLUTION

    Use a simple jQuery updating (JavaScript, jQuery is built in Wicket 6)

    The code snippet with jQuery updating

        final IModel<String> textModel = Model.of("initial text");
        final Label result = new Label("result", textModel);
        result.setOutputMarkupId(true);
        add(result);
    
        Form<String> form = new Form<>("form", textModel);
        add(form);
    
        AjaxEditableMultiLineLabel<String> textArea = new AjaxEditableMultiLineLabel<String>(
                "text", textModel) {
    
            private static final long serialVersionUID = 1L;
    
            private boolean initialized = false;
    
            private FormComponent<String> editor;
    
            @Override
            public void onEdit(AjaxRequestTarget target) {
                super.onEdit(target);
                if(!initialized) {
                    String editorId = editor.getMarkupId();
                    String resultId = result.getMarkupId();
                    StringWriter sw = new StringWriter();
                    sw.write("$('#");
                    sw.write(editorId);
                    sw.write("').keyup(function() { var str = $('#");
                    sw.write(editorId);
                    sw.write("').val(); ");
                    sw.write("$('#");
                    sw.write(resultId);
                    sw.write("').html(str); });");
                    String js = sw.toString();
                    System.out.println("Appending editor JS " + js);
                    target.appendJavaScript(js);
                    initialized = true;
                }
            }
    
            @Override
            protected FormComponent<String> newEditor(MarkupContainer parent,
                    String componentId, IModel<String> model) {
                editor = super.newEditor(parent, componentId, model);
                return editor;
            }
    
        };
    
        textArea.setCols(50);
        textArea.setRows(20);
    
        form.add(textArea);
        form.add(new SubmitLink("submit"));