Matteo Pezzanera
Matteo Pezzanera

Reputation: 21

how can i modify attributes without adding the component in Wicket?

I have to add a class to a component. I can't add the component via ajax because this is a problem with the input. My code is:

private ListView<Opzioni> setListOpzioni(boolean b) {

    return new ListView<Opzioni>("list_opzioni", opzioniDao.findAll()) {

        @Override
        protected void populateItem(ListItem<Opzioni> item) {
            erroriAssociatiAlTextField = new HashMap<>();
            List<Opzioni> opzioniCron = opzioniDao.getOpzioniFormatore();

            final Opzioni o = item.getModelObject();

            final WebMarkupContainer errorContainer = new WebMarkupContainer("errorContainer");
            errorContainer.setOutputMarkupId(true);
            errorContainer.setOutputMarkupPlaceholderTag(true);

            Boolean isSelected = false;
            Boolean isAzienda = o.getAzienda() != null ? o.getAzienda().equals(getAziendaLogged()) : false;
            if (isAdminFormatore(getUserLogged())) {
                isSelected = o.getControlFormatore() || isAzienda;
            } else {
                isSelected = isAzienda;
            }

            Boolean visibile = isSa || isSelected;

            Label name_op = new Label("name_op", o.getName());
            item.add(name_op.setVisible(visibile));

            TextField val_op = new TextField("val_op", new PropertyModel(o, "val"));
            val_op.add(new OnChangeAjaxBehavior() {
                @Override
                protected void onUpdate(AjaxRequestTarget art) {
                    if (opzioniCron.contains(o)) {
                        controllaStringa(o);
                    }
                    if (valoriScorretti == true) {
                        contatore++;
                    } else {
                         contatore = 0;
                    }
                    if (contatore > 0) {
                         ciSonoErrori = true;
                         String error = "Valori inseriti nel box " + o.getName() + " non corretti";

                    if (!erroriAssociatiAlTextField.containsKey(o)) {
                         erroriAssociatiAlTextField.put(o, error);
                    }

                    for (Map.Entry<Opzioni, String> map : erroriAssociatiAlTextField.entrySet()) {
                        val_op.error(map.getValue());
                    }
                    art.add(errorContainer.setVisible(true));
                    refreshFp(art);
                    art.add(save_btn.setVisible(false));
                    } else {
                        ciSonoErrori = false;

                        if (!erroriAssociatiAlTextField.isEmpty()) {

                            art.add(save_btn.setVisible(false));

                            if (erroriAssociatiAlTextField.containsKey(o)) {
                                    erroriAssociatiAlTextField.remove(o);

                            }

                            for (Map.Entry<Opzioni, String> map : erroriAssociatiAlTextField.entrySet()) {
                                 val_op.error(map.getValue());
                            }
                        }
                        if (erroriAssociatiAlTextField.isEmpty()) {
                            art.add(save_btn.setVisible(true));
                        }
                        art.add(errorContainer.setVisible(false));

                        refreshFp(art);

                        }
                    }
                });
                item.add(val_op.setEnabled(b).setVisible(visibile));


                item.add(errorContainer.setVisible(false));

                if (visibile) {
                    o.setModificato(true);
                } else {
                    o.setModificato(false);
                }
            }
        };
    }

With this code every time a user insert a letter inside the field the cursor go to the first position and it's impossible to use it. Is there an alternative mode to add the class dynamically?

Upvotes: 0

Views: 334

Answers (1)

user6073886
user6073886

Reputation:

With this code every time a user insert a letter inside the field the cursor go to the first position and it's impossible to use it.

That is because of the OnChangeAjaxBehavior you are using. This behavior checks after every user input if the FormComponent validates correct and if it does it will call the onUpdate method.

For a TextField without an IValidator added that means onUpdate is called after every input. If you then reprint the TextField via AjaxRequestTarget you get the behaviour of an input field where you type "backwards" as you currently do.

how can i modify attributes without adding the component in Wicket?

If you want you're changes to be visible in the browser then you need to update the component with ajax at some point. There is no way around it.

You probably have to rethink you're aproach because what you are currently doing doesn't make much sense.

At the moment you have a TextField and when the user enters something that is valid you add the css class "field-error" to the html input.

  1. Shouldn't it be the other way around and the " field-error" should get added when the users enters something that is invalid?
  2. Do you really want to validate and do an ajax update while the user enters something? Why not validate the input when the form/textfield actually gets submitted, or when the user is done typing into the field?

Edit

Instead of updating the input with the AjaxRequestTarget you could use the AjaxRequestTarget to send the jQuery command to add the css class to the input:

val_op.setOutputMarkupId(true);
val_op.add(new OnChangeAjaxBehavior() {
     @Override
     protected void onUpdate(AjaxRequestTarget art) {
          art.appendJavaScript("$('#"+val_op.getMarkupId()+"').addClass('field-error');");
    }
}

Instead of updating the whole input via ajax, this will just send a jQuery Javascript to be executed in the AjaxResponse. You can then just do the Javascript call in the page you linked and the adding of the css class will be done on client side.

The only thing you need is the id of your input so that jquery can find it. So setOutputMarkupId must be set to true and you can then get the id that wicket created by calling getMarkupId() and insert it into the javascript command.

As I already said it seems strange to me that you add the error-class in the onUpdate method. The correct way would seem to me to add the error class in the onError method (called when input is invalid) and remove it in the onUpdate (when input is valid).

val_op.setOutputMarkupId(true);
val_op.add(new OnChangeAjaxBehavior() {
     @Override
     protected void onUpdate(AjaxRequestTarget art) {
          art.appendJavaScript("$('#"+val_op.getMarkupId()+"').removeClass('field-error');");
    }

     @Override
     protected void onError(AjaxRequestTarget art, RuntimeException e) {
          art.appendJavaScript("$('#"+val_op.getMarkupId()+"').addClass('field-error');");
    }
}

Upvotes: 2

Related Questions