Jump to content

Anyone done Ajax login with bootstrap.io form validation?


Juergen
 Share

Recommended Posts

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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(…);
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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