I have a JQuery DataTable that has checkboxes to select items in it. I added j
JQuery validation such that you can't submit the form without having at least selected one checkbox. Here is what my validation looks like:
jQuery.validator.addMethod("noApplicationSelected", function(value, element, params) { return $('.cbDisplay').length != 0; },'{0}');
$('[name="cbDisplay"]').rules('add', { noApplicationSelected: ['No checkbox selected'] });
Everything works fine but my problem is that if I for example add a filter in my DataTable search such that no entries are present (empty DataTable), and I try to submit the form, it submits even though I haven't selected any checkboxes.
The reason for that I think is because the validation can't bind the rules on the checkboxes because they do not exist.
How can I fix this problem?
Edit 1:
Would adding some validation that checks for whether the DataTable is empty and a checkbox is selected fix my problem? But the issue I see with that is what do I bind this validation to? I guess I could bind it to the select all/deselect all checkbox but that doesn't make sense
Edit 2:
Demo of the probelm: https://jsfiddle.net/mu79L32w/14/
If you try to find the inputs/checkboxes inside the displayed document, you only get the rendered elements of the datatables-element. This means it is possible that you will not find any checkbox-element in the document if the filter of datatables is used. If a row is not displayed in the datatables-element it is removed from the rendered table and as a result all elements inside that row are also not available for a wrapping form-element.
But you can iterate over the data/rows of the DataTable-Object with javascript.
Here is an example on how to test if any checkbox is checked when the form submits by using jquery-validates submitHandler.
$(document).ready(function() {
let table = $('#example').DataTable({
"columns": [
{ "data": "column_a" },
{ "data": "column_b" }
]
});
function isAnythingChecked() {
let foundChecked = false;
let inputs = table.rows().nodes().to$().find('input');
for (let input of inputs) {
if (input.checked) foundChecked = true;
}
return foundChecked;
}
$("#myForm").validate({
submitHandler: function(form) {
if (isAnythingChecked()) {
alert('Yeah! A checkbox is selected');
//form.submit();
} else {
alert('Oh no! No checkbox selected');
}
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation#1.19.0/dist/jquery.validate.min.js"></script>
<link href="https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.css" rel="stylesheet"/>
<script src="https://cdn.datatables.net/v/dt/dt-1.10.18/datatables.min.js"></script>
<form id="myForm">
<table id="example" class="display" style="width:100%">
<thead>
<tr>
<th>Column A</th>
<th>Column B</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox"> Checkbox 1</td>
<td>Test</td>
</tr>
<tr>
<td><input type="checkbox"> Checkbox 2</td>
<td>Lorem</td>
</tr>
<tr>
<td><input type="checkbox"> Checkbox 3</td>
<td>ipsum</td>
</tr>
</tbody>
<table>
<button id="btn" type="submit">Submit</button>
</form>
As you suspected, you cannot bind validation to any input that does not yet exist.
I don't see enough code for a demo, so some generics below:
You do not need to write a custom method for making checkboxes required using this plugin. If the checkboxes are in a group sharing the same name, then required will make at least one from the group mandatory. See: jsfiddle.net/q357zcwy/1/
The whole point of the .rules() method is for dynamically adding removing rules after the plugin has already been initialized on the form. So if you dynamically add an input, then call .rules() on that input after it's been created. See: jsfiddle.net/q357zcwy/2/
If you only want to add required, then the easiest way to handle this is by putting the required="required" attribute on the input and my item #2 above is negated. You do not have to worry about whether it exists or when to call .rules(). Simply create the input that includes this attribute and the plugin will automatically pick it up. See: jsfiddle.net/q357zcwy/3/
<input type="checkbox" name="foo" required="required" ....
Hidden or invisible fields are always ignored by default. If your plugin is hiding any of the fields you are trying to validate, then you'll need to over-ride this behavior using the ignore option. Set ignore to []("nothing") so that nothing is ignored and everything gets validated.
ignore: []
EDIT: More notes after seeing your jsFiddle:
The .validate() method gets called once to initialize the plugin on the form. Typically on page load. However, you have it within the function that is called by your click handler, which means validation is not initialized until the button is clicked and it's repeatedly called unnecessarily every time the button is clicked.
The DataTables plugin is indeed removing the rows entirely when you search/filter the table. Although the validation plugin can handle invisible or hidden elements (see item #4 above), there is no way anyone can reasonably expect it to handle elements that no longer exist in the DOM. I find it strange that DataTables can not merely hide these rows or render them invisible rather than removing entirely.
The solution by Jan is interesting as it iterates through the DataTables object looking for checked items. However, there does not seem to be a way to properly integrate this function into the operation of the jQuery Validate plugin. While the validate plugin is normally tied to each input and automatically shows/hides messages based on rules, this "workaround" is clumsily shoved into the submitHandler, which is normally only invoked after the form is valid. It also cannot leverage the default validation messages, highlight, unhighlight, success, invalidHandler, or any of the other built-in functions.
There might be a way to leverage showErrors to show & hide the default messages programmatically based upon the iteration through the DataTables object. However, this workaround would get overly complex. You would also need to gather the name(s) of the checked object from the DataTable object in order to know which messages to toggle. Then if none of the rows exist when you want to validate, you'd have to find another way to trigger validation. Since nearly all of the default functionality of the jQuery Validation plugin would be over-written anyway, it might actually make more sense to just write your own form validation from scratch. No off-the-shelf validation plugin is going to be able to handle input elements that don't exist.
Related
I'm new to Drupal and I'm trying to create a view with many filter options,
because it has a lot of filter fields I want them to be hidden and only show the filter fields the user decides he wants to see at a given time.
I couldnit find a module to get the said affect so i tried to use panels and add my own html and jQuery custom code:
HTML
<input type="button" id="filter-selection-toggle-button" value="show filters"/>
<div id="my-filter-selection">
<input type="checkbox" value="edit-field-1">field 1</input><br/>
<input type="checkbox" value="edit-field-2">field 2</input><br/>
<input type="checkbox" value="edit-field-3">field 3</input><br/>
<input type="checkbox" value="edit-field-4">field 4</input><br/>
<input type="checkbox" value="edit-field-5">Dimention</input><br/>
<input type="button" id="filter-button" value="filters button"/>
</div>
jQuery:
<script type="text/javascript">
// We define a function that takes one parameter named $.
(function ($) {
$(document).ready(function()
{
var showCheckedFilters=function(event)
{
var x=$("input:checkbox:checked");
var y=$("input:checkbox:not(:checked)");
var checkedFilters="";//array of checked filters
var unCheckedFilters="";//array of checked filters
var toggleSpeed=event.data.toggleSpeed;
for (var i=0;i<x.length;i++)
{
checkedFilters=checkedFilters+"#"+$(x).eq(i).val()+",";
}
for (var i=0;i<y.length;i++)
{
unCheckedFilters=unCheckedFilters+"#"+$(y).eq(i).val()+",";
}
if (checkedFilters!="")
{
// remove comma
checkedFilters=checkedFilters.substring(0,checkedFilters.length-1);
$(checkedFilters+",.view-filters").show(toggleSpeed);
}
else // all are unchecked
{
$(".view-filters").hide(toggleSpeed);
}
if (unCheckedFilters!="")
{
// remove comma
unCheckedFilters=unCheckedFilters.substring(0,unCheckedFilters.length-1);
$(unCheckedFilters).hide(toggleSpeed);
}
};
// Now use jQuery with the $ shortcut again like you normally would
$("#my-filter-selection,.view-filters").hide();
//showCheckedFilters();//hide nondefault filters
$("#filter-selection-toggle-button").click(function(){$("#my-filter-selection").toggle(500);});
$("#filter-button").click({toggleSpeed:500},showCheckedFilters);
//$("#edit-submit-items-in-market").click({toggleSpeed:0},showCheckedFilters);
//to do on every reload of the filters
$(document).ajaxComplete({toggleSpeed:0},showCheckedFilters);
});
// Here we immediately call the function with jQuery as the parameter.
}(jQuery));
</script>
All seems to work fine up until the drupal filter is actually used, apparently drupal reloads the filter fields using ajax and not only the content, at which point all the filters appear again.
In order to avoid this I tried capturing the ajax call using
$(document).ajaxComplete({toggleSpeed:0},showCheckedFilters);
or adding my own call to the drupal submit button:
$("#edit-submit-items-in-market").click({toggleSpeed:0},showCheckedFilters);
both to no avail.
So:
is there a way to make sure the unchecked filters stay hidden?
is there a better solution than adding the above html piece all together?
(note I'm not versed in the drupal api so sending me to change tpl files or creating a custom module is not a very good option).
Example:
filtered:
unfiltered (after pressing apply):
Can you be more specific about what you want to filter?
Anyhow, I think you should check this module - https://www.drupal.org/project/webform_conditional
You can also cancel ajax on the advance settings in the Drupal view
I have just started using Knockout.js My form has elements which I call questions. I hide/show them based on user selections. When user hits the submit button I want to post only the visible questions at the time of submit. What I have is this:
// length of Results(questionArray) is 260
var vmToPost = viewModel;
delete vmToPost.__ko_mapping__;
ko.utils.arrayForEach(vmToPost.Results(), function (question) {
if (!(vmToPost.getQuestion(question.QuestionID()).visible())) {
ko.utils.arrayRemoveItem(vmToPost.Results(), question);
}
});
The util function arrayForEach is behaving strange. It loops through the array very differntly. I had to hit the submit button 7 times to get all the visible elements and come out of the util function. It doesnt throw any error message in the console or the fiddler.
What am I doing wrong. Please help.
Html contains a built-in way to skip items from being submitted. It's the disabled attribute, which can be controlled using Knockout with the enable or disable bindings.
<div data-bind="visible: visible">
<label>Name: <input name="name" data-bind="enable: visible"></label>
</div>
I have a plain-text representation of board of size X x Y using an underlaying 2D array presented on the screen. Each cell has either 1 or 0 as a value and there are preset array configurations that have users can choose that display on the board.
I want the users to be able to choose their own custom board configurations (i.e. picking which cells should be 1, while unchecked ones are 0). To do this, I simply set up a 16 x 16 table of checkbox inputs. At the bottom of this is a submit button where they can click to draw the board once they've chosen their configuration.
<table>
<tr>
<td><input type="checkbox"></td>
<td><input type="checkbox"></td>
...
</tr>
<tr>
<td><input type="checkbox"></td>
<td><input type="checkbox"></td>
...
</tr>
...
</table>
My question: How can I hide/display the checkboxes when necessary? I only want to display the checkbox inputs when a user specifically clicks that they want to create a custom layout. Once they select the boxes and press submit, I'll process the data, but I then also want to hide the checkboxes. Is this possible? Thanks!
In the most basic case, you could simply have something like this:
CSS:
input[type=checkbox] {
display: none; /* Make them initially hidden */
}
HTML:
<input type="button" value="Customize" onclick="showCheckboxes()"/>
Javascript:
function showCheckboxes(){
var checkboxes = document.getElementsByTagName('input')
for(var i=0; i<checkboxes.length; i++){
if(checkboxes[i].type == 'checkbox'){
checkboxes[i].style.display = 'inline');
}
}
}
You could obviously use similar logic for hiding the boxes again when some other event or interaction occurs. This assumes that all checkboxes on the page should be shown. If there are others on the page, you need to identify the ones you want to affect by name or class and check for that in the loop.
As usual, this would all be much simpler using a framework like jQuery.
Hiding the checkboxes before the form is submitted is not really a common thing to do. You could however have something like this for achieving it:
<form onsubmit="hideCheckboxes(); return true;">
Im trying to dynamically check a checkbox using JQuery 1.5, based on something the user selects from a dropdown list. When the list changes it returns to this function:
function displaySystemResults(html){
var v = html.split(",");
document.getElementById('fUpdateSystemName').value = v[0];
if (v[1] == "true"){
alert("true");
$('#fUpdateActiveFlag').setAttribute('checked','checked');
}
}
Here is the dropdown list:
<td valign="top"><form:checkbox path="fUpdateActiveFlag"
name='fUpdateActiveFlag' value="checked" /> </td>
I can't get the checkbox to put a tick in the box. Can anyone spot what im doing wrong? I know its hitting the setAttribute method as the alert box is displaying when it should be set to true.
$('#fUpdateActiveFlag') is the ID selector.
add it to your checkbox
<td valign="top"><form:checkbox ID="fUpdateActiveFlag" path="fUpdateActiveFlag"
name='fUpdateActiveFlag' value="checked" /> </td>
Also, jQuery function is incorrect. setAttribute is the JavaScript function, while it looks like you're using jQuery selector, hence the object you select is jQuery object, which does not have a method called setAttribute, instead, use .attr():
$('#fUpdateActiveFlag').attr('checked','checked')
see working example http://jsfiddle.net/ruslans/8xp9g/
Edit: as per #Dementic 's comment below, you can keep using the name attribute, but then you'll have to change your selector to:
$('[name="fUpdateActiveFlag"]').attr('checked','checked');
see working example: http://jsfiddle.net/ruslans/A4D8f/
For a custom image selection tool I would like to create form validation based on html 5 form validation.
For example my form consists of the following elements:
<form class="cms-form" action="">
<table width="800">
<tr>
<td width="30%">Name:</td>
<td><input type="text" name="name" class="cms-input-text" maxlength="127" /></td>
</tr>
<tr>
<td>Image:</td>
<td><textarea name="icon" class="cms-input-file" data-file-resource="images" data-options="{"min":1,"max":3}">/location-to-image.png</textarea></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
I have a Javascript that changes the textarea (.cms-input-file) into some html to add images and hides the original textarea.
It looks something like this:
<textarea name="icon" class="cms-input-file" data-file-resource="images" data-options="{"min":1,"max":3}" style="display: none;">/location-to-image.png</textarea>
<ul class="cms-input-file-list">
<li class="cms-input-file-item" data-image="/location-to-image.png">
<img src="/location-to-thumb.png" alt="" class="cms-input-file-item-thumbnail"/>
<span class="cms-input-file-item-title">location to image</span>
</li>
<li class="cms-input-file-add">Add</li>
</ul>
Since I have allot of existing forms using html5 form validation I would like to validate this element using the default form validation within html5 supported browsers, but using a hopefully existing event.
I'm looking for something like this:
$('.cms-input-file').on('customValidateFunction', function () {
var options = $(this).data('options');
if($(this).find('> li.cms-input-file-item').length < options.min)
{
return [false, 'Add more images.'];
}
if($(this).find('> li.cms-input-file-item').length > options.max)
{
return [false, 'Remove some images.'];
}
return true;
});
Does anyone know if something like this is possible using default html 5 events or how would I go about adding this event to the submit event? To actually trigger the default browser validation look and feel.
-- edit --
So far I have made an attempt to get this result using a div element which hides the original element. But now I need to add a pattern to the element to match according to my options. Is this possible?
Current progress: http://jsfiddle.net/jeffreydev/YyEVu/
If I understand correctly what you need, I think you can achieve what you are trying to do using the pattern attribute of any input element.
I've created a very simple form in jsfiddle illustrating this.
The idea is that you update the value of your input with whatever data you have in your model when adding or removing images. The example, just adds one letter f per icon. Then, you can create a regex to match the expected valid results. In the example, pattern="f{1,3}" means that to be valid, the content can be "f", "ff", or "fff" but nothing else, which means that it'll only accept from one to three files to be sent.
You would be using just default html5 form validation, but you may need a bit of tweaking to get it working.
However, if you try this way, you should keep a couple of things in mind:
As explained in the specs, the patttern is compiled as a JavaScript regular expression with the global, ignoreCase, and multiline flags disabled
Setting the disabled property of your input so that the user can't change it would take it out of the form, and thus it won't be validated
Applying certain styles as *display:none" to the input element can cause errors when the validation fails and the browser tries to gain focus on the element.
I hope you this helps
You can install a submit handler on the <form>, and dispatch a custom event from there.
That will look something like this:
$('form.cms-form').on('submit', function(evt) {
var frm = $(this);
var allElements = $(this.elements);
$('#errors').empty();
var errors = [];
var arg = {
reportValidationError : function( msg ) {
errors.push(msg);
},
form : this
};
console.log("all elements: ", allElements);
allElements.trigger('customValidate', [ arg ]);
if( errors.length !== 0 ) {
showValidationErrors(errors);
return false;
}
return true;
});
Then, you can "hook" the customValidate event, and install your own logic...
$('textarea[name=icon]').on('customValidate', function(evt, reporter) {
var options = $(this).data('options');
// ... your validation here ...
// for example:
var txt = $(this).val();
if( txt.length < options.min || txt.length > options.max ) {
reporter.reportValidationError('error: "icon" min/max exceeded!');
}
})
Here's an example at jsFiddle.
Edit
You can style the error reporting, and tweak the code, to look and behave however you want it to. Here's an example.
A very good jquery plugin to validate your forms is Mike Alsup one's.
You will find it here: http://jquery.malsup.com/form/
It is documented, ajax compatible.
It can do serialization for one field or for all fields inside the form, so it is a big advantage regarding your problem you could need to handle fields validation and error logic with your forms.
You could add the blockUI plugin of the same author to enhance user's experience, and don't have to manage double submission of the form when javascript is enabled.
http://jquery.malsup.com/block/
Answer from 2022: Yes, it is possible without jQuery etc.
Most browsers support Constraint Validation API (even IE 11 according to "caniuse")
The recommended practice is to listen to input/submit events and then set validity flags on the input-box.
<form>
<input type="text" required id="answer">
<input type="submit">
</form>
Validation JS:
const nameInput = document.querySelector("#answer");
const form = document.querySelector("form");
function validate(e) {
if (nameInput.value == "42") { //correct!
nameInput.setCustomValidity(""); // empty means "no error"
}
else {
nameInput.setCustomValidity("Wrong answer!"); //show error text
e.preventDefault(); //prevent form submit
}
}
nameInput.addEventListener("input", validate);
form.addEventListener("submit", validate);
The input event fires even when the value is changed programmatically
P.S. Codepen to play with: https://codepen.io/jitbit/pen/XWYZjXO