I need a little guidance. I have an HTML form comprised of a very long list of items pulled from an array generated by a database query (it's a list of university courses). Users need to be able to select as many or as few courses as are relevant to their research: because the list can have hundreds or items I have a "select all" and a "select none" function and have added a jQuery shift-select batch selector to make this as easy as possible.
However, I also want them to be able to enter some text in an input box and click APPLY to select all checkboxes where the label text pattern matches using a LIKE operator (i.e., if they want all MATH courses, or all courses of level 2xx). The project is using PHP and JavaScript/jQuery/AJAX.
I know how to pull from the database based on LIKE queries, but I'm just a bit stumped as to how best loop through the generated form and target the items that are in my form. (My PHP is pretty strong, my jQuery is a bit shaky).
The list of checkboxes is generated via a loop through the array with each item set up as follows:
$o .= '<input id="'.$rw[2].'_'.$rw[0].'"
type=checkbox name="' . $rw[2].'_'. $rw[0]. '" />';
$o .= '<label for="'.$rw[2].'_'. $rw[0].'"> ' . $rw[1] . '</label>';
$o .= '</td>';
So we end up with a simple checkbox form with a LABEL FOR and the label text, and the items are all named as the array keys.
This is the HTML output for a typical item:
<tr><td><input id="110_105" type=checkbox name="110_105" />
<label for="110_105"> PHIL233</label></td></tr>
Sorry if this description is a bit long, but what I need is an idea of how to go about looping through the form's elements after it is generated to SELECT the checkbox for every item where the pattern matches.
Hope this makes sense!
Tamra
This situation is perfect for using AJAX to filter the checkbox list. I highly advocate for this instead.
But if you need to filter on the client it's fairly easy with JavaScript.
//give the labels a class so they are easy to find
var labels = document.getElementsByClassName('course-name');
//filtering text field
var query = document.getElementById('query');
//'apply' button
var queryBtn = document.getElementById('query-submit');
queryBtn.addEventListener('click', function() {
for (var i = 0; i < labels.length; i += 1) {
var label = labels[i];
var text = label.innerText;
if (text === query.value) {
label.previousElementSibling.checked = true;
}
}
}, false);
You can try it with jQuery find method.
http://api.jquery.com/find/
With it and the "Attribute Contains Selector", you can do the trick.
http://api.jquery.com/attribute-contains-selector/
Related
I'm having a problem in a simply js function. I have a web page where I show records in a table, and when I click on an icon (which stands for 'change this record'), that cell of table should be replaced with a dropdown menu in which the user can select the new value for that record based on the available ones.
I tried in a lot of ways:
function clickOnModifyProfessor(id, professors) {
let select = document.createElement("select");
select.setAttribute("id", id);
for (let i = 0; i < professors.length; i++) {
let el = document.createElement("option");
el.textContent = professors[i]['name'] + " " + professors[i]['surname'];
el.value = professors[i]['professorID'];
select.appendChild(el);
}
//I set id=2 simply to test with one specific record, if it works I'll just set another parameter to generalize the change.
const node = document.getElementById("2");
node.textContent = '';
node.appendChild(select);
}
With this code I just get the empty table cell after clicking on the modify button, but the strange thing is that if I try to create another element (textarea, password etc) it works perfectly, so I can't understand why it does this only with the select element. I also tried by creating the whole select with option elements and taking it to the table cell by the innerHTML, but it doesn't works (as before, it works with others elements that aren't 'select').
If it can help, here is the code fragment where I call this function:
echo "<tr><td>" . $row['subjectName'] . "</td>
<td id='" . $rowsCount . "'>
<p>" . $row['profName'] . " " . $row['profSurname'] . "
<i class='material-icons' onclick='clickOnModifyProfessor(" . json_encode($row['subjectName'], JSON_HEX_APOS) . "," . json_encode($professors, JSON_HEX_APOS) . ")'>create</i>
</p>
</td>
</tr>";
PS: I also tried to print in console document.getElementById(id).innerText after I append the new 'select' element to the document and it prints correctly the options I added.
Am I making an error? I hope it's sufficiently clear.
I answer my own question with the solution I found, maybe it can be helpful for someone.
The problem is that the materialize css' select can't render on browser without starting js before, so it's necessary to add class='browser-default' when we create the select element or, if we want materialize css select style, we need to use $('select').formSelect(); after the select element has been created with its options.
I am working on a permissions page on my site and currently have it sets up with three columns Username Permissions and Action. When I press the Edit button in the Action column I want to be able to edit the Permissions column only in that specific row. Right now I have it setting both the Username and Permissions cell to be contenteditable.
Here is is my definition of my table (data being pulled from DB):
echo "<td class='username'>" . $row['username'] . "</td>";
echo "<td class='permissions'>" . $row['isAdmin'] . "</td>";
echo "<td><input type='button' class='btn btn-primary edit' value='Edit'></td>"
And Here is the script I am currently using to change each column in the row:
var $this = $(this);
var tds = $this.closest('tr').find('td').filter(function () {
return $(this).find('.edit').length === 0;
});
//console.log(tds);
if ($this.val() === 'Edit') {
$this.val('Save');
if($this.id !== '.edit') {
tds.prop('contenteditable', true);
}
}
I need it to only select the <td class='permissions'> in the current row that the button was clicked on.
What is the proper way to select only that cell in the corresponding row?
I've tried multiple ways to try and only select it from tds based on the class but have had no success.
Instead of using the rather complicated construction
var tds = $this.closest('tr').find('td').filter(function () {
return $(this).find('.edit').length === 0;
});
you could simply do
var tds = $(this).closest('tr').find('td.permissions');
to identify the target element to make editable. I assume that this code is part of the 'click'-event function for the "edit" button..
I have made a fully editable HTML Table using DataTables and some custom code. I can't share the whole code though, as it is a closed-source project for work, but I think it will be helpfull.
Take a look at my repo
Some useful notes:
1) I used Mutation Observer Api to track changes in cell values. I stored every changed cell in an array and on clicking 'Save' the array gets sent with AJAX to the back-end.
2) There is a HTML attribute called contenteditable. It lets you edit, well, the content of an element. Use that to edit the cells' values before appending them to the array. Attach an event listener to the 'Edit' button and when it is clicked, add this attribute to all the 'td' elements of your table.
3) You just send the array with values to the back-end and run some simple queries to your database.
Hope it helps you.
This is probably very simple, but am learning PHP, Javascript as I go. I find it easier to learn using real examples than the contrived examples given online.
I am creating an attendance register page, based on selecting a class, then all members of that class ordered by Surname and Firstname.
The table row has it's id set, by PHP, as the record's mem_id, and contains just forename+" "+surname, and some checkboxes.
All this is working fine, but now I have been asked to add a link so that clicking on it brings up a modal containing related data for the person selected. The extra data is already in the $a_fetch array.
Have added a glyphicon link for every row and clicking it displays a modal alright, and by having a javascript function I know I can get the row index and row id
<tbody>
<?php
while($g_fetch = $a_query->fetch_array()) {
$checked = array();
$memid = $g_fetch['mem_id'];
$name = $g_fetch['firstname'].' '.$g_fetch['lastname'];
$attendences = explode(",",$g_fetch['attend']);
for ($x = 0; $x <= 12; $x++) {
if ($attendences[$x]!="0") {
$checked[$x] = 'checked = "checked"';
}
else $checked[$x] = '';
}
echo "<tr id='".$memid."'>";
echo "<td>".$name."</td>";
echo "<td align='center'><div id='".$memid."' class='glyphicon glyphicon-info-sign' onclick='getId(this.id)' style='cursor:pointer' data-toggle='modal' data-target='#ModalCentre'></div>";
for ($y = 0; $y <= 12; $y++) {
echo '<td align="center"><input type="checkbox" value = "" '.$checked[$y].'></td>';
}
}
unset($checked);
unset($attendences);
?>
</tbody>
</table>
I am at a loss as how to proceed - is it even possible to pass data to the modal to display related data?
If it is would I need to run a new query (SELECT), or as the row is the same index as the data in the $A_fetch, and the row id has the correct mem_id is it possible to get the data from the existing $a_fetch array using either of those, or would I need to run a new SELECT?
Many thanks
There are multiple ways to provide data to the modal - and (in my opinion) it depends on how much data you need to pass to your modal and how many rows you have.
I want to describe you two ways:
Light+Easier Solution
If you don't want to display a lot of data and you have just a few rows.
The idea is to add the data directly to each div.glyphicon (as data attributes) and then use it in the modal
In your foreach add it to your model like that:
<div id='".$memid."' class='glyphicon glyphicon-info-sign' onclick='getId(this.id)' style='cursor:pointer' data-toggle='modal' data-target='#ModalCentre' data-link='".$g_fetch['additional_link'] ."' data-moreInfo='".$g_fetch['moreInfo']."'></div>
You haven't posted the modal's HTML or your JS code, but you wrote you are using bootstrap, so stick to
https://getbootstrap.com/docs/4.0/components/modal/#varying-modal-content
and fetch/set the relevant data (related clicked glyphicon) as it's described.
More complex solution
For more data / more rows. The additional data is not provided in the inital loaded HTML page - Therefore not all data needs to be loaded in the beginning.
Instead the additional data is loaded via ajax when clicking on one row.
For that you need to provide an additional endpoint (php) which provides the modal content for one row.
Check out second answer in Bootstrap 3 - How to load content in modal body via AJAX?
Basically you have a php file (e.g. getAdditionalData.php)
In this file you access the mem_id via GET
$mem_id = $_GET['mem_id'];
fetch the additional data from database
and print/render out the modal content (full html like in the second answer)
And in JS (inital page) you load the modal content onClick (fetched from php with provided mem_id as parameter)
var clicked = $(e.relatedTarget);
$(this).find(".modal-body").load("%PATH%/getAdditionalData.php?mem_id="+clicked.attr("id"));
I hope it will help you solving your problem and if you need additional infos just let me know. There are more ways to archive your goal but I think this 2 possibilities are enough in the beginning :-)
I have a simple problem, but for some reason cannot figure out the words to find a solution (or which I'm sure there are many). I'm building a simple PHP form for a user, who may have zero-to-infinite phone numbers and one-to-infinite email-addresses.
I want one PHP page which allows me to click a button like "add new phone number" and another phone number field pops up. Next to each field should be a delete icon which removes that row. When I submit the form I want to be able to process it in PHP, ideally in a simple way.
The problem is I'm manually writing out the jQuery line-by-line and trying to build a framework to make it so I can easily apply this to other fields. Then I realized it must have been done already, and I'm reinventing the wheel.
Does anyone know of any simple one-to-many tools to spare me reinventing the wheel?
UPDATE Turns out I should have been searching for "form element repeater" or "form input cloning" or some similar phrase, instead of "jquery one to many inputs". The new phrases yielded the results found in my accepted (my own) answer.
Two frameworks:
SheepIt: http://www.mdelrosso.com/sheepit/index.php?lng=en_GB&sec=home
jQuery Form Element Repeater Plugin: https://github.com/cballou/jQuery-Form-Element-Repeater-Plugin
$('.add-input').click(function(){
var num = $(this).attr('data-num'),
$newInput = $('<input data-input="' + num + '" type="tel"/>'),
$delete = $('<a class='delete'/>');
$delete.on('click', function(ev){
$newInput.remove();
});
$('#formName').append($newInput + $delete);
}) ;
Something along the lines of this should work fine. It generates a input and delete button attaching a click event to the delete button generated and uses data attributes so you can keep track of inputs through PHP.
Your html code should look like this <input name="phonenumber[]">
Your jquery code will look like this
$('#add_phonenumber').click(function(){
$('#my_form').append('<input name="phonenumber[]">'); //add
});
$('.delete_me').click(function(){
$(this).closest('span or div').find('input').remove(); // delete (NOTE: your delete button and an input must be in one container for each input)
});
<span class="inputs"><input type="text" name="phonenumber[]"><a class="delete_me">delete this input</a></span>
Your php form handler
$new = array();
$phones = $_POST['phonenumber'];
$count = count( $phones );
for ( $i = 0; $i < $count; $i++ ) {
if ( $phones[$i] != '' ) :
$new[$i]['phonenumber'] = stripslashes( strip_tags( $phones[$i] ) );
endif;
}
// now array $new contains your phone numbers, you can save it or whatever you want to do with it
As a simple alternative maybe you could have one input box and separate the multiple entries with semi-colons or some other marker. Then in the php script you could use the explode function to separate them out into an array. e.g. :
johndoe#gahoo.com; janedoe#gahoo.com;jamesdoe#gahoo.com;
This would allow cut and paste of e.g. strings of email addresses, so for some applications it might be a preferable solution, as well as requiring minimal coding
I have trouble with this code..
I'm making a "zoo system", where using button click (its value=type of animal) it adds me new item (<select> of animals) of that type. The problem I have, is that I am not able to determine (because I'm using button, not submit and its $_POSTS), which of the 10 types of animals (10 buttons with different captions (e.g. "Add birds", "Add mammals", etc.) and different values of button) was "chosen" with the click.
And when I "Add birds", I'd like to create not only the <select> with particular birds, but I also want to create next element (e.g. next <select> with the color of its feathers). For each type, I'd like to have different element that I'd like to add to that stable <select>.
In my code, there's newdiv.innerHTML = \"$animals[1]\";, because it is working well if I manually put the value inside (it generates me select of animals with id_type=1).
$anim = array();
$res = mysqli_query($db,"SELECT * FROM animals ORDER BY name");
while ($arr = mysqli_fetch_assoc($res)) {
$anim[$arr['id_type']][] = "<option value='".$arr['id_animal']."'>".$arr['name']."</option>";
$animals[$arr['id_type']]= '<select name=id_anim[]>' . implode(' ', array_values($anim[$arr['id_type']])) . '</select>';
}
$anim_type = "";
$types = mysqli_query($db, "SELECT id_type, name_type FROM type_animals ORDER BY id_type");
while ($t = mysqli_fetch_assoc($types)) {
$anim_type .= "<button type='button' name='atype' value='".$t['id_type']."' onclick=\"zoo('dynamicInput', '".$t['id_type']."');\">Add ".$t['name_type']." </button>";
}
echo"
<script type=\"text/javascript\">
function zoo(divName, atype){
var newdiv = document.createElement('div');
newdiv.innerHTML = \"$animals[1]\";
document.getElementById(divName).appendChild(newdiv);
}
</script> ";
Do you think, it's somehow possible to differentiate which of the button was pressed so I can i.e. in JS have switch where for each number (value of pressed button, value of id_type), I can specify what content should be generated?
Or is it possible to generate content with PHP instead of JavaScript (so I can use something like $_POST - although it's just a button, not a submit)?
How can I use that passed value in JavaScript code, to generate more content due to that value? I see the foolish way, to manually insert 10 values, and for everyone set it's full content. But I'd like to see the smart way (i.e. the stable core, and the switch which generates its own content for each value)..
edit for #tttpapi: the generated code is:
stable: 4x <button type='button' name='atype' value='1-4' onclick=\"zoo('dynamicInput', '1-4');\">Add birds/mammals/beasts/herbivores </button>
generated after "birds" clicked:
<select name=id_anim[]><option value='1'>Parrot</option> <option value='2'>Pelican</option> <option value='3'>Hummingbird</option></select>
And this all is, in latter code coated in:
<form method='POST'><fieldset>
<div name='dynamicInput'></div>
</fieldset></form>
Thanks a lot ;)
You can get the value of the button click with
$button = $_POST["nameOfButton"];
Here replace "nameOfButton" with "atype".
Note: You need to put the same button name tag on the different buttons.