Jump to content

Recommended Posts

Posted

Hello @ all,

I am using the following js-framework to validate my frontend forms: http://formvalidation.io/

My goal is to check if username and password match via Ajax, so the customer will see immediately if the entered values are correct or not.

For this reason I have included the following js snippet inside the template with the login form.

<?php
$ajaxlogin                   = $pages->get("template=jsonlogin");
$ajaxloginurl                = $ajaxlogin->httpUrl;
?>
<script>
$(document).ready(function() {
$('#mainlogin-form').formValidation({
    framework: 'bootstrap',
    icon: {
    valid: 'fa fa-check',
    invalid: 'fa fa-remove',
    validating: 'fa fa-refresh fa-spin'
    },
    fields: {
        user: {
            verbose: false,
            validators: {
                notEmpty: {
                    message: '<?php echo _t('Username missing! Please enter your username', 'Login');?>'
                },
                different: {
                    field: 'pass',
                    message: 'The username and password cannot be the same as each other'
                },        
            }
        },
        pass: {
            verbose: false,
            validators: {
                notEmpty: {
                    message: '<?php echo _t('Password missing! Please enter your password', 'Login');?>'
                },
                different: {
                    field: 'user',
                    message: 'The username and password cannot be the same as each other'
                },            
                remote: {
                    url: '<?php echo $ajaxloginurl;?>',
                    data: function(validator) {
                       return {
                           user: $('[name="user"]').val(),
                           pass: $('[name="pass"]').val()
                       };
                    },
                   message: 'Dont match'
                }
            }
        }
    }
});
});
</script>

This script should send the values of the fields user and pass to the backend (json file). Field username = user, field password = pass.

The backend file looks like this:

<?php
//check if password and username match 
$match = true;
$username = $input->get['user'];
$pass     = $input->get['pass'];
$u        = $users->get($username);

//check if userid and password/temp password match
if (($u->id && ($u->pass == $pass)) OR ($u->id && ($u->tmp_pass == $pass))){
   $match = true;    
} else {
    $match = false;
}
// Finally, return a JSON
echo json_encode(array(
    'valid' => $match,
));
?>

It should return true if both values match and false if not.

In this case the username check works as standalone, but the combination of username and password match not. I can also not check if the password is in the db as standalone - this is probably a reason that it is not stored as a standard value. So I guess the problem could be in the jsonfile and not in the js file.

It would be great if a user also uses this validation framework and can help me out.

Here is another link that probably can help: http://stackoverflow.com/questions/27143058/bootstrap-validator-send-all-input-field-values-to-remote-php-file

Thanks in advance

  • Like 1
Posted

Ok I have figured it out. But one problem remains: User is logged in automatically without clicking the submit button. So if the username and password are entered correctly the user is logged in. Is there a way to prevent this.

Here is the working code for others who are interested in:

Js validation code:

<script>
$(document).ready(function() {
$('#mainlogin-form').formValidation({
    framework: 'bootstrap',
    icon: {
    valid: 'fa fa-check',
    invalid: 'fa fa-remove',
    validating: 'fa fa-refresh fa-spin'
    },
    fields: {
        user: {
            verbose: false,
            validators: {
                notEmpty: {
                    message: '<?php echo _t('Username missing! Please enter your username', 'Login');?>'
                },
                different: {
                    field: 'pass',
                    message: 'The username and password cannot be the same as each other'
                },
            }
        },
        pass: {
            verbose: false,
            validators: {
                notEmpty: {
                    message: '<?php echo _t('Password missing! Please enter your password', 'Login');?>'
                },
                different: {
                    field: 'user',
                    message: 'The username and password cannot be the same as each other'
                },            
                remote: {
                    url: '<?php echo $ajaxloginurl;?>',
                    data: function(validator) {
                       return {
                           user: $('[name="user"]').val(),
                           pass: $('[name="pass"]').val()
                       };
                    },
                   message: 'Dont match'
                }
            }
        }
    }
});
});
</script>

Here is the changed code from the json file:

<?php
//check if password and username match 
$match = true;
$username = $input->get['user'];
$pass     = $input->get['pass'];
$u        = $users->get($username);
//check if log in with temp pass

if ($u->id && $u->tmp_pass && $u->tmp_pass === $pass) {
                    // user logging in with tmp_pass, so change it to be their real pass
                    $u->of(false);
                    $u->pass = $u->tmp_pass;//set temp pass value as pass value
                    $u->tmp_pass = '';//delete temp pass value
                    $u->save();
                    $u->of(true);
}
//try to login with password and username
if ($session->login($username, $pass)) {
	  // login successful
	  $match = true;
	} else {
    //password and username dont match
	  $match = false;
	}
// Finally, return a JSON
echo json_encode(array(
    'valid' => $match,
));
?>

This code line is responsible for the automatic login:

if ($session->login($username, $pass)) {.....

Is there  a way to prevent this?

I have asked a new question to this specific topic: https://processwire.com/talk/topic/13265-how-to-check-if-username-and-password-match-in-pw/?p=119972

Therefore this topic is solved.

Posted

It's probably not as feature rich, but I really like nette forms, where I can define validation rules for both client side and server side at once. The library is so nice to include a simple js file, to handle client side validation, which is additionally quite easy to enhance / change to ones specific needs.

  • Like 3
Posted

It's probably not as feature rich, but I really like nette forms, where I can define validation rules for both client side and server side at once. The library is so nice to include a simple js file, to handle client side validation, which is additionally quite easy to enhance / change to ones specific needs.

So true! The default renderer is enough 99% of the time but there is the manual rendering where you can build the markup as you like it. I've done in a recent project and it's really awesome. Will post a screenshot later.

Do you use the default validation Js or live-form-validation.js? I use the latter, the fork by Robyer, I found this to be the best maintained:

https://github.com/Robyer/nette-live-form-validation

Posted

I'm using a modified version of the default js file provided by nette. Didn't know about the other one by now. For rendering I'm using a custom Renderer class, which extends the framework's own one. This keeps it clean and is way easier than e.g. modifying ProcessWire's form markup output.

Posted

I do not use PW's form markup at all but Nette Form elements. Renderer is easy to customize, eg.

$required_asterix = Html::el('sup')->setClass('asterix')->setText('*');
$colon = Html::el('span')->setClass('colon')->setText(':');

$renderer->wrappers['form']['container'] = 'div class="form-wrapper"';
$renderer->wrappers['controls']['container'] = 'div';
$renderer->wrappers['control']['container'] = 'div';
$renderer->wrappers['control']['description'] = 'p class="form-description"';
$renderer->wrappers['error']['container'] = 'ul class="help-block text-danger form-error"';
$renderer->wrappers['label']['suffix'] = $colon;
$renderer->wrappers['label']['requiredsuffix'] = $required_asterix;

As I wrote modifying the markup this way is well enough for simpler forms, and even for larger forms if there are no fancy things.

Here is a quick screencap where I used manual rendering, which allows custom markup. Form fields are defined separately, and you can retrieve the full control, or only the label or control, error parts, etc. I like the freedom it gives.

<div class="form-wrapper" n:if="$rsvpForm">
    <fieldset>
        <legend><span><strong>Personal data</strong></span></legend>
        <p class="checkbox-wrap">

            {$rsvpForm[participation_toggle]->getControlPart()}
            <label for="cf_participation_toggle">We attend the wedding</label>
            <span class="slideToggle">{$rsvpForm[participation_toggle]->getLabelPart()}<strong></strong></span>
            <label for="cf_participation_toggle">Unfotunately we cannot attend the wedding</label>
        </p>

        <div id="personal_data">
            <div>
                <div class="input-wrap">{$rsvpForm['name']->control->cols(35)} {$rsvpForm['name']->error}</div>
                <div class="input-wrap">{$rsvpForm['email']->control->cols(35)} {$rsvpForm['email']->error}</div>
                <div class="input-wrap">{$rsvpForm['phone']->control->cols(35)} {$rsvpForm['phone']->error}</div>
            </div>
        </div>
    </fieldset>
    ...

rsvp-form.gif

  • Like 5
Posted

Just changing the markup elements wasn't flexible enough for my usecase and manually putting all those form parts in their wrapper markup isn't a option as well, as the form is dynamically adjusted to which data the current user does need to supply (by role and such things). That's why I went with the custom renderer class. Just doing a 'echo $form' does render the complete form with markup just as I need it to be.

  • Like 1
Posted

Well you can dynamically build your form too, eg.

if($user->hasRole('role_name')) {
	$form->addTextarea('result_to_see', _t('What is the result you would like to see?', 'Form'), 50, 3)
	    ->setRequired(_t('Required field', 'Form'))
	    ->setOption('character-counter', array('mode' => 'down', 'msg' => _t('%d characters left', 'Form')))
	    ->setAttribute('data-autosize')
	    ->setAttribute('maxlength', 500);
}

$preferences = array(
    'trial' => 'I would prefer to start with a small trial project to see how we can work together.',
    'resolve' => 'I have a specific inquiry, and just want this issue to get resolved.',
    'best-roi' => 'I want to go big. Let’s see how we can achieve the best return on investment overall.'
);

if($something) {
	$preferences['anotherItem'] = 'Anther radio button';
}

$form->addRadioList('preferences', _t('Please set the preference that best suits you', 'Form'), $preferences)
    ->setRequired(_t('Required field', 'Form'));

echo $form;

But you see what fits better for your project.

  • Like 1
Posted

And if you've more than a handful of fields you save yourself the hassle of writing all those if statements.

<?php 

$needed = [
	'my-field',
	…
];

$addIfNeeded = function($fieldname, callable $callback) use ($form, $needed){
	if(!in_array($fieldname, $needed)) return;
	$callback($form, $fieldname);
};

$addIfNeeded('my-field', function($form, $fieldname){
	$form->addText($fieldname, __('My Field'))
		->setRequired(__('My field is required'));
});

$addIfNeeded(…);
$addIfNeeded(…);
Posted

 Will post a screenshot later.

That's cool, but please do not forget to publish your Nette Forms module either when the time comes ;)

(Just kidding, I'm sure you will not "forget" it.)

Posted

Maybe you should wait for my Nette forms module indeed. Seem like I don't manage to hide it forever :) It's functional and I use it on many production site but given the complexity of forms it's still only in alpha state. It's more about how I solved integrating Nette forms into PW, but still, there are areas I haven't explored.

  • Like 4

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...