Hiding/Displaying Forms (Checkbox forms) -- javascript - javascript

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;">

Related

Editing properties of objects individually and need "edit" boxes to open dynamically for each property

The backend is Python with Django Models. Below is what I have in the User Inteface.
When the user clicks the "edit" pen I want a textbox input to show up right beneath the previous value, also a "submit changes" button pops up at the top of the page. The user needs to be able to edit as many properties as desired and then submit all changes at once. My object has over 75 properties so the javascript will get really long and cumbersome if I create a unique function for each property. So far I have this:
html:
<button id="edit_submit" type="submit" form="job_text_edit">Commit Changes</button>
<form id="job_text_edit" action="pass to backend"></form>
<table class="z-depth-3">
<tr>
<td style="width: 200px">Job Name:</td>
<td>
{{job.job_name}}<i class="tiny material-icons" onclick="jobEdit()">edit</i>
<input id="job_name_i" name="job_name_i" type="text" form="job_text_edit">
</td>
</tr>
<tr>
<td>Work Schedule:</td>
<td>
{{job.work_schedule}}<a><i class="tiny material-icons" onclick="jobEdit()">edit</i></a>
<input id="work_schedule_i" name="work_schedule_i" type="text" form="job_text_edit">
</td>
</tr>
</table>
javascript:
<script>
$(document).ready(function(){
$('#edit_submit').hide();
$('#job_name_i').hide();
$('#work_schedule_i').hide();
})
function jobEdit(){
$('#edit_submit').show();
$('#job_name_i').show();
$('#work_schedule_i').show();
}
</script>
The problem is that when you click any "edit" pens, all the edit boxes will pop up. Is there a way to let the function know which one was clicked so I can implement conditional statements in the function to show only the necessary boxes? I tried passing in a string with the input id but the function throws errors when given string arguments. Any help is greatly appreciated!
when you pull data from the back end, you need to pull through an id or some unique value also.
This value would be unique to each indiviudal row you show in your screenshot above, or an element in that row.
Then when you render your html, append the id (unique value) to the end of the current id (html id on the element)
So for example, where you have input id="job_name_i", you can add (append) the unique value (id) to the end of it upon rendering.
You can then, instead of passing through your function call in the onclick (and defining the onClick in the html), you can set up an event listener in the init part of your javascript like so:
$("[id^=job_name_i]").on('click', event => {
const clickedElement = $(event.target);
});
The above will listen for a click on any element that begins with
job_name_i (remember your unique value will be appended to the end of it.
So the above would go inside the below block.
$(document).ready(function(){
});
You now have access to the specific clicked element on the page, to do as you need, adding stuff below or above it. So you can access the ID with by using event.target.id and you can pass that in to your function.
Something like the following.
function jobEdit(id){
$(id).show();
// OR
$(someelement + id).show();
}

How can I hide this table row based on the value of an input field 4 levels down

I have a table with lots of rows
I have a filter to hide these rows based on the content of a child element (an input field) several levels down within the row
The input field within the row is wrapped several times. I can't manage to hide the row based on that inputs value.
Here's how a row looks:
<tr class="acf-row" data-id="row-13">
<td class="acf-field acf-field-date-picker acf-field-5de02ec006a2e" data-name="datum" data-type="date_picker" data-key="field_5de02ec006a2e">
<div class="acf-input">
<div class="acf-date-picker acf-input-wrap" data-date_format="dd.mm.yy" data-first_day="1">
<input type="text" class="input hasDatepicker" value="24.03.2020" id="dp1582735317447">
</div>
</div>
</td>
</tr>
Please note that there are more siblings on each level than I've put in here for readability. But the hierarchy is as displayed here.
Then I've got this input field to define what we want to filter:
<input placeholder="Datum filtern" type="text" id="datefilter" style="padding:5px; width:150px;">
And last but not least the jquery:
$( "#datefilter" ).change(function() {
var filterdate = $("#datefilter").val();
jQuery('.input.hasDatepicker').each(function() {
var currentElement = $(this);
var dateinfield = currentElement.val();
if( dateinfield !== filterdate){
$(this).closest('.acf-row').hide();
}
});
});
Currently it hides all the rows, not just those with a different value. What should happen is that only the rows get hidden where the value of #datefilter is different from the value of .input.hasDatepicker
I tried a few things like trying to use .parent().parent()... but didn't get it to work. Help would be greatly appreciated.
Here's a jsfiddle with the whole table including all siblings:
https://jsfiddle.net/59by3w7o/
UPDATE:
I think I can now say for sure the issue is 2 instances of the input element in each row. Here's a jsfiddle with only that and no noise:
https://jsfiddle.net/8k41xy6u/
How could I solve that? I tried playing with :first but couldn't get it to take the first within each .acf-row and not the very first in the whole document.
From the updated JSFiddle, a table row looks something like:
<tr class="acf-row">
<td>
<div class="acf-input">
<div>
<input class="input hasDatepicker" type="text" value="26.03.2020">
<input class="input hasDatepicker" type="text" value="10:00">
</div>
</div>
</td>
</tr>
And now the problem becomes clear. In the JS, .each() iterates over everything with the classes .input and .hasDatepicker. Both your inputs match that, so it will test both of them. If the value of the either one does not match your filterdate that row will be hidden. But the 2nd input value is a time, and that will never match a date, no matter what the date is - so every row will always be hidden.
There are 2 obvious ways to tackle this - 1) make the inputs distinguishable, so you can target just the date input in your filter comparison, OR 2) somehow target just the first input in the set of 2.
The first option (make them distinguishable) is by far the best, as the second relies on the layout of the HTML. It could happen in future that you'll do a redesign and the inputs won't be in the same order, or even in the same <div>, and then your JS will break. That might even happen without you doing it or even knowing about it if the HTML is autogenerated by some 3rd-party library (eg ACF/Wordpress), and a plugin update changes things. But if you can distinguish the inputs then you can target the right ones no matter where they are on the page.
To make them distinguishable, you could add a class, eg:
<input class="input hasDatepicker date" type="text" value="26.03.2020">
Then update your JS to target only those:
$('.input.hasDatepicker.date').each(function(i) {
If changing the HTML isn't an option, then you'll have to rely on and make use of position. Iterate instead over all div.acf-inputs, and find the first input in each:
$('div.acf-input').each(function(i) {
var dateinfield = $(this).find('input.input.hasDatepicker').first().val();
// ...
Working JSFiddle (of option 2).

JQuery validation on not existing checkbox

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.

Javascript Bootstrap randomize checkboxes

I have the following situation I can not solve. I would be very thankful if anyone had an idea:
My webpage contains a table of players. Each line (player) contains two checkboxes: One that selects if the player is active (checked) or not, the other which team he/she belongs to (checked=Team 1; unchecked=Team 2).
So each line looks sth like this:
<tr>
<td><input id="plyr2_active" type="checkbox" name="plyr_active[]" value="2"></td>
<td><input type="checkbox" id="plyr2_team" name="plyr_team[2]" data-on-color="danger" data-off-color="success" data-on-text="RED" data-off-text="GREEN" checked value="1"></td>
</tr>
I'd like to add a button that, when clicked, will run a function that randomizes the teams of the ACTIVE players. Meaning that the players will be shuffled and half of them belong to one, the other half to the other team.
What I tried: Get all checkbox states in an array, then shuffle() the array and try to change the checked-state via bootstrap. Miserably failed :-(
Any help will be much appreciated. Thanks!!
Okay, this should help to get you started. It shows how to pull a list of active players (using jQuery) from your table.
Assuming you have a button with an id of 'shuffleBtn':
<button id="shuffleBtn">Shuffle<button>
and a table with id 'players':
<table id='players'>
:
</table>
-
$("#shuffleBtn").click(function() {
var newPlayerArray = [],
id = 1;
$("#players tr td:first-child").each(function() {
if ($(this).find('input:first').prop('checked')) {
newPlayerArray.push(id);
}
id++;
});
console.log(newPlayerArray);
});
This will display an array of the active players (assuming the first row is player 1, the second player 2, etc.) on the console.
Example: [1,3,4]
It then iterates each row () and grabs the first column (). Then for each of those it finds the first <input> and checks if the 'checked' property is present (this means the checkbox has been clicked).
I am just pushing the row index (starting at 1) so you may need to change how you interpret the associated player.

dygraphs setVisibility() with muiltiple plots on page

I've been working with dygraphs and have gotten a webpage working well with check boxes to toggle on and off visibility for a potentially infinite number of dygraphs on a page.
I am however now stuck when I've added buttons to set the values all on or all off.
I've found a basic example I've followed: http://dygraphs.com/tests/color-visibility.html which has the ID names of the check boxes 0-3. This works well with one plot, or even with multiple plots as long as I don't have to call the ID of the check boxes. I had the whole system working with repeating the ID numbers.
However when I add a button to automatically check the box I need uniquely identified check boxes or else it only checks and unchecks the first set of boxes. Then once I rename the check box ID the original visibility function doesn't work.
HTML:
<input type=checkbox id=0 onClick="change(this,plotname)" checked=true > A
<input type=checkbox id=1 onClick="change(this,plotname)" checked=true > B
<input type=checkbox id=2 onClick="change(this,plotname)" checked=true > C
<input type=checkbox id=3 onClick="change(this,plotname)" checked=true > D
<input id="all_On" type="button" value="All On" onclick="checkTheBoxes([true, true, true, true],<%= chartnumber %>)">
JS code:
function change(element,name) {
name.setVisibility(element.id, element.checked);
}
function checkTheBoxes(tfarray,section) {
for (var j = 0;tfarray.length;j++){
document.getElementById(j).checked = tfarray[j]
document.getElementById(j).onclick()
//I have been using the section input to identify plots with the renamed IDs
}
}
I believe the problem lies in the "this" call when passing through the change function. When I probe with Firebug the element is input#3 if I click check box number 3 and this works. However if I have renamed the ID something like plot2box3 the firebug element is input#plot2box3 which I believe the setVisibilty function doesn't know what to do with.
The question is then, how do I keep the "this" reference outputting the correct element while being able to uniquely call the check box.
Thanks!

Categories