Using Foundation 6 Abide, I've created a custom validator that needs to check a username field against a pattern AND also have it reach out to the server to see if the username is already registered. When the custom validator is executed, it first tests the username against a regex pattern - if that succeeds, it then executes an ajax call to the server to see if the username exists. Since javascript doesn't wait, the custom validator function returns "true" indicating everything is OK. When the ajax call completes, if the username was found, it calls the "addErrorClasses" on the field. This works perfectly, however I'm concerned that since the validator previously returned "true" since it didn't want to wait on the ajax, that now there's no way to return "false" and the form will think it is in a valid state.
QUESTION: Does calling the addErrorClasses function mark the field as invalid, which would then make the form in an invalid state?
Foundation.Abide.defaults.validators.validate_username =
function($el,required,parent) {
// parameter 1 is jQuery selector
if (!required) return true;
let val = $el.val();
// Step 1 - check that it meets the pattern
if (!val.length)
return true;
let valid = new RegExp(username_pattern).test(val);
if (!valid)
return false;
// Step 2 - check that the username is available
$.ajax({
url: "http://localhost:3000/users/"+val,
}).done(function(data) {
$('#demo-form').foundation('addErrorClasses',$el);
console.log(data);
}).fail(function() {
// do nothing for now
});
return true;
};
Yes by calling the addErrorClasses will mark that control as 'invalid' but it depends where and how you call the method.
Since you are executing the ajax(i.e. asynchronous) it returns true by default. By that time your control will be 'valid' and when the ajax receives the response from the 'url' it sets 'invalid' based on your code.
When you try to submit the form the foundation framework resets all the control i.e. it removes all the 'data-invalid' attribute and then executes all the default and custom validators. Still your method return true. It doesn't wait for the response from your ajax.
The form will be submitted even if you have errors in your control.
Related
I'm creating a form with Angular2 and I created two custom validators for email address field.
The first validator checks for email validity, the second (async) validator checks if email address already exists on database.
In addition I would like to add a third validator for another verification.
Here is my code:
'email': ['', [validateEmail(), thirdValidator()], asyncValidator]
The behaviour that I want is the following:
Only when the first validator validates the control, the second validator should start. And only when the second validator terminates then the third validator can start its validation.
How to reach this?
Validators.compose method should do the job, example:
let formControls = {
'oldPassword': new FormControl({ value: ''}),
'newPassword': new FormControl({ value: ''}, Validators.compose([customValidator1, customValidator2]), customAsyncValidator)
};
Composed validators work simultaneously, meaning we can have multiple errors on the control at the same time (each validator attaches its own error if validation failed). If we need to have only one error on the control at a time, we can 'chain' validators by checking the status of the previous validation before performing next one. Something like this:
let customValidator2 = (ctrl: FormControl): any => {
if(ctrl.hasError('customValidationError1')) {
// there is the error attached by customValidator1,
// skip executing customValidator2 (nullify its error)
return null;
}
let isInvalid = true; // some condition...
return isInvalid ? { customValidationError2: true } : null;
}
This way we can accomplish 'ordering' the validators by their priority for example.
I noticed that the Select2 widget serving options with remote data was making a call even when I enter just empty spaces. This usually returns me an empty array, but I would like to eliminate this call altogether.
So here is what I did.
The Select2 plugin allows us to define our own AJAX call handler via the transport option.
From the docs :
Select2 uses the transport method defined in ajax.transport to send requests to your API. By default, this transport method is jQuery.ajax but this can be changed
So here is how you can eliminate the unnecessary call altogether.
$('select').select2({
...
ajax: {
transport: function (params, success, failure) {
if (!params.data.q.trim().length) {
return false;
}
var $request = $.ajax(params);
$request.then(success);
$request.fail(failure);
return $request;
}
}
...
})
A more detailed snippet at my blog.
Select2 has a minimumInputLength option which will handle this for you. It will display a notice when the user needs to enter more characters, and then send the request out when enough have been entered.
I am using CakePHP 2.4.
I want my frontend make api calls to my CakePHP backend using ajax.
Suppose this is to change passwords.
Change password action can throw the following application errors:
old password wrong
new password and confirm new passwords do not match
In my frontend, I have a success callback handler and a error callback handler.
The error callback handler handles all the non 200 request calls such as when I throw NotFoundException or UnAuthorizedAccessException in my action.
The success callback handler handles all the 200 request calls including of course, the above 2 scenarios.
My questions are:
Should I continue to do it this way? Meaning to say, inside all success callback handler, I need to watch out for application success and application error scenarios.
Should I send application errors back with actual HTTP error codes?
if I should do 2, how do I implement this in CakePHP?
Thank you.
Don't use http error codes for system errors like:
old password wrong
new password and confirm new passwords do not match
etc etc...
Now using success handler you can show messages and code flow as:
Create Ajax post or get to submit the form, I am showing you post example
var passwordValue = $('#password').val();
$.post( "/updatePassword", { passwordText: passwordValue })
.done(function(response) {
if(response.status === 'Success'){
// Success msg
// whatever
}else{
// Error msg
// whatever
}
});
json response would like:
{
"status": "Failed/Success",
"message": "old password wrong."
}
Create one function in controller
public function updatePassword() {
$myModel = $this->MyModel->find('first' // YOUR CODE LOGIC);
if($this->request->is('ajax') {
$this->layout=null;
// What else?
echo json_encode($myModel);
exit;
// What else?
}
}
Do something like this, hope it will solve your query!
Not sure if SFDebug is any help in this situation. I am making an ajax post using jQuery. Which retrieves JSON data in my action URL and then makes a call to the Model method that executes the action. The part until my action URL, and the jQuery call to it work fine. With the data transmitted from the client to the server well received and no errors being made.
It is the part where it calls the method on the Model that is failing. My jQuery method looks like this:
$.post(url, jsonData, function(servermsg) { console.log(servermsg); }) ;
My server action is like this
public function executeMyAjaxRequest(sfWebRequest $request)
{
if($request->isXmlHttpRequest())
{
// process whatever
$servermsg = Doctrine_Core::getTable('table')->addDataToTable($dataArray);
return $this->renderText($servermsg);
}
return false;
}
The method of concern in the Table.class.php file looks like this:
public function addDataToTable($dataArray)
{
// process $dataArray and retrieve the necessary data
$data = new Data();
$data->field = $dataArray['field'];
.
.
.
$data->save();
return $data->id ;
}
The method fails up here in the model, when renderText in the action is returned and logged into the console, it returns the HTMl for SFDEBUG. Which indicates that it failed.
If this was not an Ajax call, I could debug it by seeing what the model method spat out, but this is a little tedious with Ajax in the mix.
Not looking for exact answers here, but more on how I can approach debugging ajax requests in a symfony environment, so if there are suggestions on how I can debug this, that would be great.
You must send cookie with session ide key via ajax
(Assuming you have XDEBUG configured on the server)
In order to trigger a debug session by an AJAX request you have to somehow make that request to send additional URL parameter XDEBUG_SESSION_START=1. For your example:
$.post(url + '?XDEBUG_SESSION_START=1', jsonData, function(servermsg) { console.log(servermsg); }) ;
You can also trigger it via cookie, but appending URL parameter usually easier.
I have a custom event that I want to fire using jQuery's trigger method:
$(wizard).trigger('validatingStepValues');
Then in the wizard's current step code, I subscribe to this event as follow:
$(wizard).bind('validatingStepValues', function (){
// Validating step's form data here; returning false on invalid state.
});
Then in my wizard, again I want to be able to stop user from going to the next step, if a false value is returned from validation process? I'd like to have something like:
$(wizard).trigger('validatingStepValues', validReturnCallback, invalidReturnCallback)
Have you considered using something like:
function wizardValidator(successCallback, failureCallback) {
return function() {
// Validating step's form data here;
if (wasValid && successCallback) {
successCallback();
}
else if (! wasValid && failureCallback) {
failureCallback();
}
return wasValid;
};
}
$(wizard).bind('validatingStepValues', wizardValidator(validReturnCallback, invalidReturnCallback));
This requires that you know the callbacks that you want to use at the time you bind the event listener. If you want to be able to use different callback functions at different times, you could define additional event types, like:
$(wizard).bind('validatingStep2Values', wizardValidator(validStep2ReturnCallback, invalidStep2ReturnCallback));
$(wizard).bind('validatingStep3Values', wizardValidator(validStep3ReturnCallback, invalidStep3ReturnCallback));
Alternately, events that you create by calling trigger() propagate up the DOM hierarchy. Returning false an event handler cancels this propagation. So you could bind your desired success callback function as an event listener on your wizard's parent node. That won't do anything to allow your failure callback to be executed, however.