As I'm building form elements dynamically I want to be able to check and see if a form field is required or not via a custom validation rule. The problem is that when I add a custom validation rule, it forces the field to not be empty. If I allow the field to be empty, it doesn't check my custom validator unless something is entered in the field.
How can I check in a callback whether to allow or not a field as required?
In my SubmissionsTable
public function validationDefault(Validator $validator)
{
$validator
->add("custom_value_q", [
"custom" => [
"rule" => [$this, "customFieldIsRequired"],
"message" => "Message Here"
]
]
);
return $validator;
}
public function customFieldIsRequired($value, $context)
{
//logic here
return true;
}
Returning true in your custom one when empty $value is passed in should do the trick.
If you want the field to allow empty string (= empty), use allowBlank('custom_value_q') on top, logically you don't need to invoke the custom validator function then, that's why it is bypassed in the empty case.
//UPDATE
You do, however, have the option to provide a callback for allowEmpty(), with this it should be possible to only invoke the custom validation rule if you really want it (if the field needs to be validated because non blank).
$validator->allowEmpty('fieldname', function ($context) {
return !isset($context['data']['description']) || $context['data']['description'] !== '';
});
I know this is a bit old, but I'm facing the same problem, and as I see in github the discussion about it is still open (https://github.com/cakephp/cakephp/issues/8925 and https://github.com/cakephp/cakephp/issues/12484).
In this case, when you have a field that may be empty on some situations (may be if other field was filled), you can do this:
$validator->allowEmptyString('field_a', function ($context) {
// check whether the field can or cannot be empty
return $canBeEmpty;
});
as this may be incorrectly evaluated when an empty form is built (for new entities) as all fields are empty probably, you may have to add the attribute required => false to the form input, if not the field would be marked as required and ask to be filled mandatory.
While having to instruct the form helper whether the field should or shouldn't be required is far from ideal, it's not a big deal, and works to validate entities and modeless forms as well.
Only for validating entities, according to this (https://github.com/cakephp/cakephp/issues/12484#issuecomment-414465002) you may use application rules, which are evaluated only when the entity is being persisted, so a field can be allowed to be empty in validations and then application rules will be applied anyway.
Related
I am using angular-schema-form, and ran into a problem that when I load a schema and a form from a server using REST, the validation sometimes did not kick in. I could post a schema even though some fields were required.
How can I always be sure that the required fields in the form has to be filled in by the user before posting?
I found that using $scope.$broadcast('schemaFormValidate'); before submitting the form works (from the docs).
$scope.onSubmit = function(form) {
// First we broadcast an event so all fields validate themselves
$scope.$broadcast('schemaFormValidate');
// Then we check if the form is valid
if (form.$valid) {
// ... do whatever you need to do with your data.
}
}
However, we can not disable any buttons beforehand.
#John you can set a value in your model that is part of a display condition. That allows you to hide the buttons on submit and then re-enable them when you are ready for the user to submit the form again for any reason.
Looks like Syphon is currently serializing every form field regardless of its state. Is there a way to easily tell Syphon to not serialize disabled fields?
Standard form submit does not include disabled fields and neither does JQuery serialize() method.
Since my primary concern was with disabled checkboxes getting serialized I was able to stop it from serializing those by adding this validator:
Backbone.Syphon.KeyAssignmentValidators.register("checkbox", function ($el, key, value) {
return $el.prop("checked") && $el.is(":enabled");
});
Note: this is a global change and effects all views.
I have a webform with some normal fields, but also some hidden fields which are set to Secure value (allows use of all tokens), so I am able to use tokens.
How do I pass values from JavaScript into those hidden fields so they are submitted with the form?
I tried using the %post[f1], %post[f2], and %post[f3] tokens, but I still don't know how to add those values with JavaScript.
You can use some basic jQuery for this.
$('input[name=INPUT_NAME]').val('NEW_VALUE');
To fully comply with Drupal theming, you probably want to wrap this up in a Drupal behavior:
(function ($) {
Drupal.behaviors.CUSTOMNAME = {
attach: function(context) {
$('input[name=INPUT_NAME]').val('NEW_VALUE');
}
}
})(jQuery);
...and of course change INPUT_NAME with the name attribute of the hidden input field and CUSTOMNAME with a descriptive camelcase name (e.g ChangeHiddenValuesForm).
As a final note: be sure to include this javascript file on the page of your form.
EDIT:
Sorry, I overlooked the Secure value reference.
Anyway, if you want the value to be secure then you shouldn't be altering it by Javascript as anyone can change it to whatever he or she likes through the DOM... That's why Webform implements the Secure value feature: the value does get submitted along with the form but simply won't be sent to the end user's browser and hereby disabling possible abuse. (For the record: Secure value uses the 'value' type from Drupal's Form API)
If you do want to change such a hidden value, you should opt for Hidden element (less secure, changeable via JavaScript) which already mentions its ability to be changed through Javascript and then use the Drupal behavior described above. Only if you do it like this it gets printed as a hidden input.
If you just want to add some JavaScript then use drupal_add_js(), for example in hook_preprocess_page() in a theme.
function mytheme_preprocess_page(&$vars, $hook) {
drupal_add_js(drupal_get_path('theme', 'mytheme') . '/mytheme.js');
$vars['scripts'] = drupal_get_js();
}
I need to update the model of a text field, then fire validation to show the user visual feedback that it is a valid entry.
I have tried two methods, but I can only get one of the requirements to work at the expense of the other.
First option: http://jsfiddle.net/TZQjS/
// changing the model in controller updates the field
// but the `required` directive will not run.
$scope.populateValid = function () {
$scope.testField = 'yes, yes, yes';
}
Second option:http://jsfiddle.net/R3b7Y/
// `$setViewValue()` of the ngModel API updates the model
// but two-way binding seems to fail
$scope.populateValid = function () {
$scope.testForm.testField.$setViewValue('yes, yes, yes');
}
How can I make both things happen, that is update the field with text, and also run validation immediately after?
I have read in places of $parsers and $formatters but I cannot understand how to use them in this context - many discussions talk about them in terms of custom validation directives.
Validation is firing as expected in your first option, but you can't see it because your second CSS rule is too stringent. You have:
input.ng-invalid.ng-dirty {
background-color: #FA787E;
}
input.ng-valid.ng-dirty {
background-color: #78FA89;
}
ng-valid and ng-dirty are complementary so they can be used together or separately as required. If you use them together as you have, you are ANDing them. A model has to be valid AND dirty to match the second rule. But in your case you only want to show that the model has been validated, so remove ng-dirty from the second rule.
Notice that if you remove ng-dirty from both rules, the view will show invalid before the user has entered anything. This isn't what we usually want, so here is a good example of when the classes should be used together.
The Backbone documentation says:
Model.set will fail if validation fails - it won't set the value therefore it won't trigger any callback. We can pass { silent: true } to Model.set - then it will set the value but won't trigger any callback neither.
So,
Why does Backbone Model require a valid state to simply set an attribute value? What if we want to set attributes as the user interacts with the UI, but the model is not valid yet? It means change callbacks are unavailable unless we pass { silent: true } then manually trigger the change?!
Please say you know a better way of handling this :)
I'm not sure how to answer the Why questions but you could say that there are arguments for why it is good that set runs validations. For instance, it makes it dead simple to do client side validation in real time.
If your problem could be solved by only validating the value that is currently being changed by the user, you can do that by combining your validate method with the hasChanged method.
For example something like this:
Backbone.Model.extend({
defaults : { name : "" },
validate : function (attrs) {
var errors = {};
if(this.hasChanged("name") && attr.name.length == 0) {
errors.name = "Need a name yo!";
}
//...
if(_.keys(errors).length > 0) {
return errors;
}
}
})
In Backbone whenever you call set on model , It keeps track of what attributes of model has been changed and what attributes are newly added.Calling validate allows it be more efficient in doing it .Passing {silent:true} as options in set function causes validate and change to not execute so if doesnt fire any change events.
If you want to set attributes as the user interacts with the UI, but the model is not valid yet
In this case you can set the change in a plain object make sure object keys are sames as model's attribute and then at some point just set in your model.
var uiChanges = {name:'x'}; //just fill it with your changes
ur_model.set(uiModel); //then set it ,this way it fires change events only once
To check the diff between your plain object and model you can use the
ur_model.changedAttributes(uiChanges);
changedAttributes -
Return an object containing all the attributes that have changed, or false if there are no changed attributes.
You can further use it save only those attributes that have changed rather than saving entire model again.