Problems, need help? Have a tip or advice? Post it here.
7 posts Page 1 of 1
Hey everyone,

I've been working on the extended users module a lot recently.

Something I've gotten stuck on is form validation, we have an "Edit profile" page, where of course you can edit your user information.

I would like to add some validation to the "E-mail" input, in fact I'd like it to behave similar to the password validation, having a "Repeat e-mail" input, I'd like the validation only to throw an error IF the e-mail has been changed (By default the input is filled with the users normal email). Then I'd like the validator to throw an error if the input isn't the same as the "Repeat E-mail" input.

Obviously I don't want another editable for the repeat e-mail, we just want to validate it on the page at time of hitting save.

I've been looking through forums and docs on databound forms as well as normal form validation, I see no way to really do this.

I can create a second input for a "Repeat E-mail" text box and custom validate this to be "Required" and "Validator=matches_field:extended_user_email" but this doesn't allow users to change other parts of their profile without having to enter their email into the repeat e-mail field, which is undesirable.

Any help would be appreciated.
Image
I could add the algorithm:
Code: Select all
<cms:if  frm_password ne existing_password >
  <cms:if frm_password_repeat ne frm_password >
         <cms:set stop_processing = 'New password doesn't match' />
  </cms:if>
</cms:if>

<cms:if "<cms:not stop_processing  />" >
   .. proceed with saving form and redirect..
<cms:else />
  <cms:show stop_processing /> (or/and [i]cms:set_flash[/i])
</cms:if>

That's right, for some things, like custom validation, it's actually good to get hands dirty and write it yourself. :) The above code uses frm_ variables, generated by submitted form, available in common k_success block.

My Documentation, Addons, Functions.
Join COUCH:TALK telegram channel
This won't help with the first part of the problem, whereby the first email input is databound, thus it's always filled with the users email, but if they do not wish to change their email the second input type which is just text will be empty (Thus the form will always error as the two fields are not the same).

This means the users are required to re-type their e-mail every time they wish to change any of the details on their account. We require the validation so that users do not incorrectly change their e-mail and lose access to the account entirely, but we also don't want them to have to re-type the e-mail into the input every time they change it.

I could probably easily fix this with javascript, filling the second email input with the contents of the first one on page-load, but it's a rather messy fix that I was hoping couch could do on its own.
Image
Dave, please take a look at the following topic -
viewtopic.php?p=18954#p18954

I think we can modify that solution to cater to your use-case. The custom validator should check the main email field to see if it has been modified ($f->modified) and then check that the second field contains the same value as the first.

Do let me know if you happen to require my help.
Thanks @KK, I've tried this now. I tried what I thought would work but it doesn't seem to be, I'm sure I've done something wrong but not entirely sure what, my code is below:

Code: Select all
function validate_email_changed( $field, $args ){
   $val1 = trim( $field->get_data() );
   $args = trim( $args );
   
    $check_fields = 0;
    foreach( $field->siblings as $f ){
        if( $f->name==$field->name ){
         $label = $f->label;
            if( $f->modified ){
                $check_fields = 1;
            }
            break;
        }
    }
   
    if( $check_fields ){
        foreach( $field->siblings as $f ){
            if( $f->name == $args ){
      $val2 = trim( $f->get_data() );
                if( $val1 !== $val2 ){
                    return KFuncs::raise_error( $label . "Fields do not match" );
                }
                break;
            }
        }
    }
}


Is this somewhat correct? It doesn't seem to do anything when used on the front-end, my template code is this:

Code: Select all
   <div><cms:input name='extended_user_email' type='bound' validator='validate_email_changed:repeat_email' /></div>
         
   <div><cms:input name='repeat_email' type='text' label="Repeat E-mail:"/></div>
Image
Dave, we cannot use the databound field to attach the validator as databound fields use only the validators used while defining their editable regions (i.e. via <cms:editable /> tag).

We cannot attach the validator to the second field (repeat email) either because validators kick in only when a field contains some value (no use validating a blank value) or is a required field (now a check is required because a required field cannot be left empty) - your second field cannot be either.

So, exactly as we did in the example post I referred you to (viewtopic.php?p=18954#p18954), we'll have to use a third (hidden) field just to hold the validator.

Your form now becomes this -
Code: Select all
E-mail:<br />
<cms:input name='extended_user_email' type='bound' /><br />

Repeat E-mail:<br />
<cms:input name='repeat_email' type='text' label="Repeat E-mail:" /><br />

<!-- this field serves only to run the validator -->
<cms:input type="hidden" name="delivery_address" label='Repeat E-mail' value="1" validator='my_match_fields=extended_user_email & repeat_email' />

Our hidden field above uses a validator named 'my_match_fields' which is a very generic validator that will match two fields only if the first field has been modified.
As you can see, we provide it with the names of the two fields as argument (separated by '&').

Following is the code for the validator. Please put it in your 'addons/kfunctions.php' file -
Code: Select all
// Matches the value of two fields only if the first field has been modified
function my_match_fields( $field, $args ){

    // get the name of the two fields from the passed args string
    list( $main_field, $repeat_field )= array_map( "trim", explode( '&', $args ) );
    if( empty($main_field) || empty($repeat_field) ) return;

    // find the main field and check if it is in modified state
    $value_to_match = null;
    foreach( $field->siblings as $f ){
        if( $f->name==$main_field ){
            if( $f->modified ){
                $value_to_match = trim( $f->get_data() );
            }
            break;
        }
    }

    if( !is_null($value_to_match) ){
        // find the repeat field and match its value with the main field's value
        foreach( $field->siblings as $f ){
            if( $f->name==$repeat_field ){
                $val = trim( $f->get_data() );
                if( $val != $value_to_match ){
                    return KFuncs::raise_error( "Fields do not match" );
                }
                break;
            }
        }
    }
}

This validator, as I noted above, is pretty generic and could come in useful in other situations too.

Hope it helps. Do let me know.
@KK Ah, thank you! I understand now, I missed the line in the referred post about the hidden field - my lesser experience with databound inputs showing through. Your solution works perfectly, thanks.
Image
7 posts Page 1 of 1