kamil
kamil

Reputation: 3512

Feedback panel added but does not show all messages

I have some basic form when you type email, old password, new password and repeat new pass for your profile modify. What I'm trying to achive is to display feedback msg when pass is wrong. A piece of code looks like this:

public class EditProfileForm extends Form<Void>
{
private static final long serialVersionUID = 1L;

// El-cheapo model for form
private final ValueMap properties = new ValueMap();

private ModalWindow modalWindow;

@SpringBean
UserManager userManager;

@SpringBean
Validator validator;

private User user;

private static final String EMAIL = "mp-email";
private static final String OLD_PASS = "mp-oldpass";
private static final String NEW_PASS = "mp-newpass";
private static final String NEW_PASS_REPEAT = "mp-newpassrepeat";

private static final String ERROR_WRONG_PASS = "Wrong pass";
private static final String ERROR_PASS_DIFF = "Pass diff";
private static final String ERROR_EMAIL_INVALID = "Wrong email";
private static final String ERROR_EMAIL_EXISTS = "Email used";

public EditProfileForm( String id, final ModalWindow modalWindow,final User u )
{
    super( id );
    this.user = u;
    this.modalWindow = modalWindow;

    add( new TextField<String>( EMAIL, new PropertyModel<String>( properties, EMAIL ) ).setRequired(true).setOutputMarkupId(true) );
    add( new PasswordTextField( OLD_PASS, new PropertyModel<String>( properties, OLD_PASS ) ).setOutputMarkupId(true) );
    add( new PasswordTextField( NEW_PASS, new PropertyModel<String>( properties, NEW_PASS ) ).setOutputMarkupId(true) );
    add( new PasswordTextField( NEW_PASS_REPEAT, new PropertyModel<String>( properties, NEW_PASS_REPEAT ) ).setOutputMarkupId(true) );

    final FeedbackPanel feedbackPanel = new FeedbackPanel( "feedback" );
    feedbackPanel.setOutputMarkupId( true );
    //feedbackPanel.setMaxMessages( 5 );

    add( feedbackPanel );

    AjaxSubmitLink closeBtn = new AjaxCloseCancelBtn( "close-x", this );
    AjaxSubmitLink cancelBtn = new AjaxCloseCancelBtn( "cancel", this );

    add( new AjaxSubmitLink( "save", this )
    {
        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit( AjaxRequestTarget target, Form<?> form )
        {
            if ( !user.getCryptedPassword().equals( CypherUtil.encodeMd5( getOldPassword() ) ) )
            {
                error( ERROR_WRONG_PASS );
            }
            else if ( !getNewPassword().equals( getNewPasswordRepeat() ) )
            {
                error( ERROR_PASS_DIFF );
            }
            else if ( !validator.validateEmailFormat( getEmail() ) )
            {
                error( ERROR_EMAIL_INVALID );
            }
            else if ( validator.emailExists( getEmail() ) )
            {
                error( ERROR_EMAIL_EXISTS );
            } else 
            {
                //save user data
            }
        }

        @Override
        protected void onError( AjaxRequestTarget target, Form<?> form )
        {
            target.add( feedbackPanel );
        }
    } );

    add( closeBtn );
    add( cancelBtn );
}

/**
 * @return
 */
private String getEmail()
{
    return properties.getString( EMAIL );
}

/**
 * @return
 */
private String getOldPassword()
{
    return properties.getString( OLD_PASS );
}

/**
 * @return
 */
private String getNewPassword()
{
    return properties.getString( NEW_PASS );
}

/**
 * @return
 */
private String getNewPasswordRepeat()
{
    return properties.getString( NEW_PASS_REPEAT );
}

}

Now when I leave these forms empty, I receive nice feedback msg that there fields are required. Meanwhile, when I type wrong pass, email or whatever I got nothing, and my server log leaves msg like this:

WARNING: Component-targetted feedback message was left unrendered. 
This could be because you are missing a FeedbackPanel on the page.  
Message: [FeedbackMessage message = "Wrong pass", reporter = save, level = ERROR]

The form is within a WebPage which is a popup:

public class ProfilePopup extends WebPage
{
private static final long serialVersionUID = 2929269801026361184L;

public ProfilePopup(final ModalWindow modal, final User user) 
{
    add( new EditProfileForm("profileModifyForm", modal, user).setOutputMarkupId(true) );
}
}

and HTML, placing feedback outside the form didn't help either :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body class="stats-popup-body">
<div class="stats-popup" id="car-info-edit-popup">
    <p class="popup_title"> Edytuj Profilu </p>
    <form wicket:id="profileModifyForm" class="stats-popup-form">           
        <div>
            <label class="popup_field_label">Email:</label>
            <input type="text" wicket:id="mp-email" />
        </div>
        <div class="clear9"></div>
        <div>
            <label class="popup_field_label">Stare hasło:</label> 
            <input type="password" name="E-mail" title="E-mail1" id="E-mail2" wicket:id="mp-oldpass" />
        </div>
        <div>
            <label class="popup_field_label">Nowe hasło:</label>
            <input type="password" wicket:id="mp-newpass" />
        </div>
        <div>
            <label class="popup_field_label">Powtórz nowe hasło:</label>
            <input type="password" wicket:id="mp-newpassrepeat" />
        </div>
        <span wicket:id="feedback"></span>
        <div class="button-box-bottom">
            <input class="btn btn_save" style="margin-right: 9px;"
                wicket:id="save" type="button" value="Zapisz"
                onmousemove="this.className='btn btn_save btn_hover'"
                onmouseout="this.className='btn btn_save'" /> 
            <input
                class="btn btn_cancel" wicket:id="cancel"
                value="Anuluj" type="button" 
                onmousemove="this.className='btn btn_cancel btn_hover'"
                onmouseout="this.className='btn btn_cancel'" />
        </div>
        <div class="stats-popup-close-x" wicket:id="close-x"></div>
    </form>
</div>
</body>
</html>

Upvotes: 1

Views: 9788

Answers (1)

Xavi L&#243;pez
Xavi L&#243;pez

Reputation: 27880

It's bad practice to perform input validations in onSubmit, because once you get there, (invalid) input has reached the Models. As you already are experiencing, onSubmit is invoked after the validation phase has ended, so the input will be considered valid, and therefore Form.onError will not be invoked.

Use a FormValidator instead (add an IFormValidator to the Form in your constructor), if you require to perform not so simple validations or validations that involve two or more components' inputs. Remember that user input will have not reached the component's Models in FormValidator.validate(), so you'll need to use Component.getConvertedInput() to get the input to be validated.

If your validations involve only one component, and operate only over its input, it might be recommendable to use an IValidator instead.

Also, notice that Wicket provides validators that perform some of the validations you'd like to perform: EqualPasswordInputValidator and EmailAddressValidator can be useful to you.

For instance:

emailField.add(EmailAddressValidator.getInstance());
form.add(new EqualPasswordInputValidator(passwordField, passwordRepeatField));

Take a look at this (somewhat outdated) wiki page for information on FormValidators: Validating related fields

Upvotes: 11

Related Questions