How do I validate multiple checkboxes, using Statamic forms? - statamic

I'm using Statamic CMS
I've got a checkbox group with two checkboxes, I'd like both of them to be checked before the form will submit.
Setting the field as 'required' half works. The form will error if nothing is checked, but it submits if one of the boxes is ticked.
I can see under the validation tab, there's a list of additional rules. But I'm not sure which rule to use.
If it helps, this is what the HTML checkbox group looks like:
<div>
<label>Contact permissions</label>
<span>Please tick both checkboxes</span>
<label>
<input type="checkbox" name="checkboxes[]" value="gdpr" />
Please contact me with the details I've provided
</label>
<label>
<input type="checkbox" name="checkboxes[]" value="terms" />
I agree with the terms and conditions
</label>
</div>
I'm using the {{ fields }} tag to generate the HTML
Within the CMS, under the validation tab, there's a link to the Laravel docs. As I want to validate two checkboxes, I think I need the required_with: rule, but I can't get it to work...
required_with: is looking for two values, the example shows this:
required_with:foo,bar,..
The values of the checkboxes are, value="gdpr" and value="terms" so I (wrongly) assume this should work...
required_with:gdpr,terms
After saving the changes and testing the form, it still submits? Even though only one of the checkboxes might be ticked...
What is the correct syntax/values to use to get this to work?

:) foo,bar in the docs are field names in your form. What you're doing with gdpr,terms are values.
Plus, since both your buttons are named checkboxes[], the form is validating that if either one is selected, then it should be passed. Hopefully this helps!

Related

AngularJS retrieve from object based on entry in ng-repeat input

This application is for running a writing contest.
Coodinators are assigning entries to judges for them to judge. I have three sets of data I retrieve from the server, a judge list, an entries list and an assignment list that ties the two together. There can be a variable number of input fields...if a judge has agreed to judge 4 entries, there will be 4 inputs...if 7, then 7.
I have all of that working OK, but only insofar as the entry number can be input and the data updated.
Now I would like confirm that the entryID IS a valid ID by checking the list and also to show a field or two on the screen so the coordinator knows that they typed in the right entry.
The relevant section of the HTML
<div ng-app>
<div id="assignment" ng-controller="AssignData" ng-init="JudgeID=107;CategorySelect='MS';PublishSelect='P'">
<div ng-show="loaded">
<form class="entryform ng-cloak" name="assignform" ng-submit="sendForm()">
<p>Entry numbers assigned to this judge</p>
<p ng-repeat="assign in (formassigns =(assigns | filter:AssignedJudge))">
<input type="text" ng-model="assign.entryid" required/>
{{entries.authorname}} {{entries.entrytitle}}
</p>
<button type="submit">Save Assignments</button>
<p>This will keep the assignments attached to this judge.
You will be able to send all of your assignments to all
of your judges when you are finished.</p>
</form>
</div>
</div>
</div>
The part that I haven't been able to figure out is how to make entries.authorname and entries.entrytitle show up when the user types in an entryid that is in entries.entryid.
assigns and entries are both arrays of records using JSON
assigns is JSON made up of assigns.id, assigns.judgeid, assigns.entryid.
entries is JSON made up of entries.entryid, entries.entrytitle, entries.authorname
When assigns arrives, entryid is empty. The form is used to fill in the entryid and when it is filled in, I'd like to be able to show next to it the title and authorname for that entry.
NOTE: I've added some important information at the end of this answer. So please read to the end before you decide what you're going to do.
You're going to have to do something that does the look up.
Also a few other changes I'd add, mostly so you can actually validate the items in your repeat.
(There's a summary of what I did after the psuedo code below).
<div ng-app>
<div id="assignment" ng-controller="AssignData"
ng-init="JudgeID=107;CategorySelect='MS';PublishSelect='P'">
<div ng-show="loaded">
<form class="entryform ng-cloak" name="assignform" ng-submit="sendForm()">
<p>Entry numbers assigned to this judge</p>
<p ng-repeat="assign in (formassigns =(assigns | filter:AssignedJudge))"
ng-form="assignForm">
<input type="text" ng-model="assign.entryid"
ng-change="checkEntryId(assign, assignForm)"
name="entryid" required/>
<span ng-show="assignForm.entryid.$error.required">required</span>
<span ng-show="assignForm.$error.validEntry">
{{assignForm.$error.validEntry[0]}}</span>
{{assign.entry.authorname}} {{assign.entry.entrytitle}}
</p>
<button type="submit">Save Assignments</button>
<p>This will keep the assignments attached to this judge.
You will be able to send all of your assignments to all
of your judges when you are finished.</p>
</form>
</div>
</div>
</div>
Then in your controller, you'd add a function like so (be sure to inject $http or a service you wrote to pull the values from the server):
$scope.checkEntryId = function(assign, form) {
$http.get('/CheckEntry?id=' + assign.entryid,
function(entry) {
if(entry) {
assign.entry = entry;
form.$setValidity('validEntry', true);
} else {
form.$setValidity('validEntry', false, 'No entry found with that id');
}
}, function() {
form.$setValidity('validEntry', true, 'An error occurred during the request');
console.log('an error occurred');
});
};
The basic idea above:
Use ng-form on your repeating elements to allow for validation of those dynamic parts.
Create a function that you can pass your item and your nested form to.
In that function, make your AJAX call to see if the entry is valid.
Check the validity based on the response, and call $setValidity on your nested form you passed to the function.
Use ng-show on a span (or something) in your nested form to show your validation messages.
Also, assign your checked entry to your repeated object for display purposes. (you could use a seperate array if you want, I suppose, but that would probably get unnecessarily complicated).
I hope that helps.
EDIT: Other thoughts
You might want to wrap your call in a $timeout or some sort of throttling function to prevent the entry id check from spamming yoru server. This is an implementation detail that's totally up to you.
If this is a check you do all over the place, you'll probably want to create a directive to do it. The idea would be very similar, but you'll do the check inside of a $parser on the ngModelController.
The method I showed above will still actually update the model's entryid, even if it's invalid. This is usually not a big deal. If it is, you'll want to go with what I suggested in "other thought #2", which is a custom validation directive.
If you need more information about validation via custom directives I did a blog entry on that a while back

web2py form creation

I'm trying to create a form in web2py.
I'm not sure on the correct syntax and don't understand from the examples in the site how this is done. Could someone give a better explanation?
How is a simple form like this created?
<form>
<select>
<option>Paint</option>
<option>Brushes</option>
<option>Erasers</option>
</select>
Quantity: <input type="text" />
<input type="submit" />
</form>
How can I validate more complex forms?
items = ['Paint','Brushes','Erasers']
form = FORM(
SELECT(*items),
INPUT('Quantity', _type='text'),
)
return dict(form=form)
(in view):
{{ extend 'layout.html' }}
{{ =form}}
To validate this form, or a "more complex" form:
(in controller)
form = FORM(...) # This is the same form def as above, must be before form.process()
if form.process().accepted:
# Valid!
else:
# invalid.
If you have a more specific question, I'll attempt to answer it, but I highly recommend you check out the book and try to create and validate your own simple forms. You can use the welcome app as a place to start. Or you could google around for web2py apps and download and play with them.
Read these two chapters in their entirety and I'll help you with anything web2py in the future (there will be a quiz!):
Database Abstraction layer (important for unlocking the full power of web2py's DB-driven forms):
http://web2py.com/books/default/chapter/29/6
Forms and Validators (everything you ever needed to know about creating forms and linking it to data:
http://web2py.com/books/default/chapter/29/7

Dynamically-Sized List of Fields in Yesod

In HTML, multiple fields can be specified with a non-unique name like so:
<input type="checkbox" name="breakfast" value="eggs">
<input type="checkbox" name="breakfast" value="bacon">
so that, when submitted, query parameters get passed like (if both boxes are ticked) breakfast=eggs&breakfast=bacon. The CGI specification states that this should be interpreted as an array or list of values, and this technique is also useful for dynamically-sized lists of inputs:
<input type="text" name="url">
<input type="button" value="Moreā€¦"
onclick="var s = document.createElement('input');
s.type='text';
s.name='url';
this.form.appendChild(s);
return false;">
However, I can see no way to get list-valued inputs from a form in Yesod. Is there any way to do such a thing?
Most of the prebuilt fields work on inputs with a single input (with a notable exception for multiSelectField). To achieve what you're looking for, you probably want to create a custom Field. Notice that the fieldParse function takes a list of Text values, specifically to allow your use case.
The chapter on forms includes a section on custom fields.

Add logic to a form when Javascript is disabled

I'd like my form to include a certain value if the quantity is equal to 1 (via a text box).
I've managed to show what the total cost is using JavaScript and I could submit it with this value but I'm worried that when JavaScript is turned off the user will be able to submit the form without the extra fee being added. Therefor escaping the fee.
<form>
<label>Qunatity</label>
<input type="text" name="qyt" />
<input type="text" name="fee" value="250" />
<div class="total">[whatever the total is]</div>
<input type="submit" value="submit" />
</form>
Is there a way I can submit this form so that it submits 250 only if a quantity of 1 is added to the form? I'd like to avoid using a select input.
Will I need to split my form out into two stages to achieve this?
You need to check your logic in server-side code.
Most people have Javascript enabled, so you should do it in Javascript to provide a better experience, but you must always reproduce the logic on the server.
If you need to validate your input without JavaScript, have a server-side component (PHP?) to do the job and return the same form with an error message if no quantity was given. That way you don't have to split your form into two steps.
The best/safest way to handle this would be to do your total calculation on the server side. That way the data you store will always be correct.

jQuery ajaxSubmit(): ho to send the form referencing on the fields id, instead of the fields name?

im pretty new to jQuery, and i dont know how to do that, and if it can be done without editing manually the plugin.
Assume to have a simply form like that:
<form action="page.php" method="post">
Name: <input type="text" name="Your name" id="contact-name" value="" />
Email: <input type="text" name="Your email" id="contact-email" value="" />
</form>
When you submit it, both in 'standard' way or with ajaxSubmit(), the values of the request take the label of the field name, so in the page.php i'll have:
$_POST['Your name'];
$_POST['Your email'];
Instead i'll like to label the submitted values with the id of the field:
$_POST['contact-name'];
$_POST['contact-email'];
Is there a way to do that with jquery and the ajaxsubmit() plugin?
And, maybe, there is a way to do it even with the normal usage of a form?
p.s: yes, i know, i could set the name and id attributes of the field both as 'contact-name', but how does two attributes that contain the same value be usefull?
According to the HTML spec, the browser should submit the name attribute, which does not need to be unique across elements.
Some server-side languages, such as Rails and PHP, take multiple elements with certain identical names and serialize them into data structures. For instance:
<input type="text" name="address[]" />
<input type="text" name="address[]" />
If the user types in 1 Infinite Loop in the first box and Suite 45 in the second box, PHP and Rails will show ["1 Infinite Loop", "Suite 45"] as the contents of the address parameter.
This is all related to the name attribute. On the other hand, the id attribute is designed to uniquely represent an element on the page. It can be referenced using CSS using #myId and in raw JavaScript using document.getElementById. Because it is unique, looking it up in JavaScript is very fast. In practice, you would use jQuery or another library, which would hide these details from you.
It is reasonably common for people to use the same attribute value for id and name, but the only one you need to care about for form submission is name. The jQuery Form Plugin emulates browser behavior extremely closely, so the same would apply to ajaxSubmit.
It's the way forms work in HTML.
Besides, Id's won't work for checkboxes and radio buttons, because you'll probably have several controls with the same name (but a different value), while an HTML element's id attribute has to be unique in your document.
If you really wanted, you could create a preprocessor javascript function that sets every form element's name to the id value, but that wouldn't be very smart IMHO.
var name = $("#contact-name").val();
var email = $("#contact-email").val();
$.post("page.php", { contact-name: name, contact-email: email } );
This will let you post the form with custom attributes.