Unable to get element id dynamically in javascript - javascript

I have a list of students that I am looping through and adding to my page. Each student has a unique ID, and when getStudentInfo is invoked, it does something with the id. The problem is that whichever student I click, I get back the same id, belonging to student1.
Where am I going wrong?
foreach ($students as $student) {
echo '<tr>';
echo '<td>
'.$student[student_permalink].'
<input type="submit"
value="info"
onclick="getStudentInfo()"
class="student-name-btn"
id="'.$student[student_permalink].'"
/>
</td>';
}
js:
function getStudentInfo() {
var studentLink = $('.student-name-btn').attr('id');
console.log(studentLink);
}

Your code is selecting all the buttons on the page with that class and than reads the id of the first one in the list. You are not limiting it to the one that was clicked.
What most people would do is add events with jQuery and not inline.
//needs to be loaded after the element or document ready
$(".student-name-btn").on("click", function() {
console.log(this.id);
});
For yours to work, you would need to pass a reference to the button that was clicked.
onclick="getStudentInfo(this)"
and than change it to use the node passed in
function getStudentInfo(btn) {
var studentLink = $(btn).attr('id');
console.log(studentLink);
}

You can pass the reference to the element being clicked on the onclick event
foreach ($students as $student) {
echo '<tr>';
echo '<td>
'.$student[student_permalink].'
<input type="submit"
value="info"
onclick="getStudentInfo(this)" // << added this which refers to the input
class="student-name-btn"
id="'.$student[student_permalink].'"
/>
</td>';
}
And then use that to fetch the id in the js
function getStudentInfo(el) {
var studentLink = $(el).attr('id');
console.log(studentLink);
}

Don't use inline events - there's no need to clutter up the HTML with that. You have a common class on your element, so just make a jQuery handler and use an instance of this
$('.student-name-btn').click(function() {
var id = this.id;
});

Like #epascarello alluded to, you are not selecting the button that was actually clicked. What you should do is have your event handling in your JS, not in the HTML so you can see better how it works and use the this keyword within the closure to reference the clicked button.
$(document).on('click', '.student-name-btn', function(evt) {
// Prevent default if trying to do your own logic
evt.preventDefault();
// Need to use the "this" keyword to reference the clicked element
var studentId = $(this).attr('id');
console.log(studentId);
});

You can do this without inline JavaScript and since you're using jQuery drop the onClick() and the form element:
echo '<tr>';
echo '<td id="'.$student['student_permalink'].'" >
'.$student['student_permalink'].'
</td>';
You also need to quote the identifier in the array variable, 'student_permalink'.
The jQuery will be this:
$('td').click(function() {
var studentLink = this.id;
console.log(studentLink);
});

Related

Change a button's class using js when php is displaying the buttons in a while loop

`<?php
$i = 0;
$testcount = 0;
while($testcount < 8) {
if($i == 0) {
?>
<input id="info" type="hidden" value="hi">
<?php
} else if ($ == 1) {
?>
<input id="info" type="hidden" value="test">
<?php
}
?>
<button onclick="test()" class="btnT">Hello</button>
<?php
$testcount++;
}
?>
<style>
.test1 {
background-color: cyan;
color: black;
}
</style>
<script type="text/javascript">
function test () {
$(".btnT").addClass("test1");
}
</script>`
Ignore the if statement, I have not yet implemented it to the js
I am displaying buttons using php while loop without any text nor class. A class is determined using an if statement using php where they will hold a hidden input value which will then be pushed to javascript which will then add a class depending on the value of the hidden input, I am then trying to remove and add another class to only one individual button displayed in the while loop. I either get the first button to get the change, or it changes all of the buttons, and not the individual button that I clicked. Please help, Thank you!
My biggest question is how to make each button inside the while loop to have the event occur individually, instead of all of them. I know that it is because I have the code to add a class to the button class, I tried replacing the button class with an id, but that way, only the first button will get the new class added and not the rest of the buttons. Hopefully there is a solution for each button to act separately
When you create your while loop you can append the $testcount to the end of an ID for the button, this way each button will have its own unique ID, but still have a 'template' name that you can use in javascript.
<?php
$i = 0;
$testcount = 0;
while($testcount < 8) {
echo '<button id="btn'.$testcount.'" onclick="test('.$testcount.')" class="btnT">Hello</button>';
$testcount++;
}
?>
Afterwards you should get 7 buttons with ID's btn1, btn2, btn3, btn4... etc
Then in Javascript you can run a function based off each button like this:
function test(x) {
var myButton = document.getElementById('btn' + x);
myButton.classList.add("test1");
// Any more JS logic you have
}
When you click, for example, button #2, the ID of that button should be 'btn2'. The onclick of the button will send the number '2' as an argument to the JS function. The variable myButton will get the element by the ID of the btn + the number you gave it to create a string like 'btn2', then based off that you now know which button was pressed, and you are able to run actions based off that. Using your example you added the class 'test1' to that button.

How can I use one event handler for multiple radio buttons?

I want mutliple radio buttons (number unknown, because they get created dynamcially) to have the same onClick or onChange event, whichever fits the best. I found examples for jQuery but not pure Javascript. Should i just loop trought all radio buttons on the form?
They get created in php like so:
//DB Connection already established
$sql = "SELECT * FROM users";
$results = $dbConnection->query($sql);
if($result->num_rows > 0){
while($row = $result->fetch-assoc()){
echo "<li><input type=radio name=all_users[] value='". $row['E-Mail'] . "'/>" . $row['Name'] . " " . $row['Lastname'] . "</li>";
}
}
else
{
echo "<p>No users found</p>";
}
How can i do that loop? Or is there any more common way of doing that?
If one of them get's clicked i want their value as a parameter for the event, in only one function.
Or Should i just add onclick=myfunction(this) into the php file?
I want multiple radio buttons (number unknown, because they get created dynamically) to have the same onClick or onChange event.
If one of them get's clicked i want their value as a parameter for the event, in only one function.
Let's assume that your PHP has rendered the list items and you have a common function called myFunction() which you want to use to log it's parameter to your console:
function myFunction(val){
console.log("The value is " + val);
};
Now if I understand you correctly, you want to run the above function whenever one of the rendered radio buttons are clicked and to pass the value of the value attribute of the radio button that was clicked as a parameter for the above function.
Firstly, you need to assigned all the rendered radio button in your list to a variable:
var x = document.querySelectorAll("li input");
Secondly, since x is a collection of objects (here, all the radio buttons rendered), you will now have to map through each item on x using forEach and assign a click listener on each radio button which runs the ClickItem()function passing it the item's defaultValue as a parameter val like this:
x.forEach(function(radio) {
radio.addEventListener('click', function() {
var val = this.defaultValue;
myFunction(val);
});
});
jsFiddle: http://jsfiddle.net/AndrewL64/2y6eqhb0/56/
However, if by value, you mean the content after the input tag but still inside the respective li tag, then you just need to make slight changes to the above code like this:
Firstly, to prevent the selector from querying li elements from other parts of the page, you need to wrapped your list items with a div or a ul having a unique ID like this:
<ul id="someList">
//create your list items here
</ul>
Secondly, you need to assigned all the rendered list items to a variable:
var x = document.querySelectorAll("#someList li");
Thirdly, similarly to what we did above, since x is a collection of objects (here, all the list items rendered), you will now have to map through each item on x using forEach and assign a click listener on each list item which runs the ClickItem()function passing it the item's innerText as a parameter val like this:
x.forEach(function(radio) {
radio.addEventListener('click', function() {
var val = this.innerText;
myFunction(val);
});
});
jsFiddle: http://jsfiddle.net/AndrewL64/2y6eqhb0/58/
Actually the JQuery make it easier, but you can do the same with pure JS.
the real concept is to capture the event bubbling, try this:
fatherElement => element that is not dynamic
fatherElement.addEventListener("click", function(event){
if(event.target.type == 'radio'){
//do something
}
});
Use this echo line instead yours:
echo "<li><input onchange='yourOnChange(event)' type=radio name=all_users[] value='". $row['E-Mail'] . "'/>" . $row['Name'] . " " . $row['Lastname'] . "</li>";
I add onchange='yourOnChange(event)' there. And of course remember to add proper js function e.g function yourOnChange(e) { console.log(e); } to your web page.
Or Should i just add onclick=myfunction(this) into the php file?
Yes, you can do that. In that case code will be;
<li><input onclick='myclick('". $row['E-Mail'] ."')' type=radio name=all_users[] value='". $row['E-Mail'] . "'/>" . $row['Name'] . " " . $row['Lastname'] . "</li>"
Now in JS code myclick(email) function can handle anything with email argument.
Pure JS solution:
var inputs = document.getElementsByTagName('input');
for(var i = 0; i < inputs.length; i++) {
if(inputs[i].type.toLowerCase() == 'radio') {
if(inputs[i].checked)
{
//if radio button is checked
myClick(inputs[i].id, 'checked') //you can get anything apart from id also
}
else
{
//if radio button is not checked
myClick(inputs[i].id, 'unchecked') //you can get anything apart from id also
}
}
}
myClick(id, stat)
{
//YAY!! I have got the id
}
You can do a for of loop if you have querySelectorAll.
Here is an example:
const radios = document.querySelectorAll('input[type=radio]');
for (const element of radios ) {element.addEventListener('click', function(event) {
console.log(event.currentTarget)
})
}
Using pure JS you can select your radio buttons and add event listeners like so:
const radios = document.querySelectorAll('input[type=radio]');
radios.forEach(radio => radio.addEventListener('change', e => {
// radio is your radio button element
});
Same with jQuery:
$('input[type=radio]').change(() => {
//your code goes here
});

javascript function only works for first input box in example

I'm echoing rows of $data inside input boxes. The javascript function below copies the input value to the clipboard upon clicking the input box. The problem is the function only works for the first input box and not subsequent echoed ones. I think I need to assign a unique id to each input box and I'm not sure how to do this.
// for each row it is echoing the following:
echo '<input id="copy-text" type="text" value="'.$data.'" size="50">';
<script>
document.getElementById("copy-text").onclick = function() {
this.select();
document.execCommand('copy');
}
</script>
ID should always be unique. When you have multiple IDs with same value javascript looks for the first match with that id and skips the rest.
If you are looping through each row, use an index like this
echo '<input id="copy-text_'.$i'" type="text" value="'.$data.'" size="50" onclick="copy($i)">';
<script>
function copy(index) {
var elem = document.getElementById("copy-text_" + index);
elem.select();
document.execCommand('copy');
}
</script>
Give the elements a class:
echo '<input class="copy-text" type="text" value="'.$data.'" size="50">';
And have a single script tag that finds all those elements and binds the event handler to them:
function handler() {
this.select();
document.execCommand('copy');
}
Array.from(document.querySelectorAll('.copy-text'))
.forEach(function(element) {
element.addEventListener(handler);
});

How to compose multiple $(document).ready() function

I have a function which creates dynamic <select>. I have to make it a multiple select options, so I have to initialise it as well.
The function is called multiple times; here's the function:
function renderTimezoneFilterStringCriteria($filterKey,$onChange,$r,$c,$for)
{
echo '<script>
$(document).ready(function()
{
$("#zoneFilter_criteria_'.$for.'_'.$r.'_'.$c.'").multiselect({
includeSelectAllOption: true,
enableFiltering: true,
enableCaseInsensitiveFiltering: true,
maxHeight: 150
});
});
</script>'.'<div class="time_zone_list"><select name="rules['.$r.']['.$c.']['.$for.'_timezone]" class="input_field zonefield" id="zoneFilter_criteria_'.$for.'_'.$r.'_'.$c.'" style="width:30%; margin-right:5px; float:left;">';
foreach ($this->timezoneArrayNotDefault as $k => $val) {
$selected = '';
$val_array = explode(")",$val);
if (isset($val_array[1]) && trim($val_array[1]) == trim($filterKey)) {
echo $selected = SELECTED;
}
echo '<option value="' . $val . '"' . $selected . '>' . $val . '</option>';
}
echo '</select></div>';
}
Now, as you can see, the html is made as php string (my client stated that by this way, the html loads faster so he used this technique, and U can't convince him to alter to another way.
Now let's come to the point: if the function is called multiple times, then it's also causing multiple $(document).ready(function(){});
Is there any way, that I can have only $(document).ready(){}); and initialise the multiple drop-downs in some other way??
Set a flag variable.
$firstCall = TRUE;
renderTimezoneFilterStringCriteria($filterKey,$onChange,$r,$c,$for, &$firstCall);
And check it:
function renderTimezoneFilterStringCriteria($filterKey,$onChange,$r,$c,$for, &$firstCall)
{
if($firstCall) {
echo '<script> $(doucment).ready(function() { ... ';
//your document.ready here
$firstCall = FALSE;
}
// your other stuff here
}
UPD: The better solution probably is to make single function wich echoes your document.ready, and call it once.
Here is an example of just rebinding your code when you add the new html.
http://jsfiddle.net/64e41LL9/
Html
<div id="container">
<button class="button-item">I am a button</button>
</div>
<br/>
<button id="add-html" >add button</button>
<br/>
<button id="rebind" >rebind</button>
Jquery
$(document).ready(function(){
//function to rebind
function rebind() {
$('.button-item').click(function(){
alert("Im binded");
})
}
//initial bind on page load
rebind()
//adding new html thats unbinded
$("#add-html").click(function(){
$("#container").append('<button class="button-item">I am a button</button>')
})
//calls function to bind new html
$("#rebind").click(function(){
rebind()
})
})
So essential what is happening here is when the page loads you will initially bind the alert code to the button but when you append new html to the page you will see the new button won't fire the on click event even though it has the same class. This is because its not binded. Once you click that rebind button it will rebind all the buttons with that class(button-item). You can use the same concept but it will call the rebind function everytime you add your dynamic html.

How to refresh DOM with newly created elements

I know this question was asked several times, but couldn't get the answer that works for me so here I am with my case.
I'm trying to make a jQuery plug-in that's add contact form to a certain page(It's not like there is no such a plug-ins but let's say I do this just for educational reasons). It is searching for <div id="add_contacts"></div> and creates the form in this div.
jQuery
$(document).ready(function(){
$('#add_contacts').append('<div class="contact-from"></div>');
$('<form></form>',{id:'new_contact'}).appendTo('.contact-form');
$('<div>',{class:'contact_user_name'}).appendTo('#new_contact');
var name_field = $('<input>',{
name:"contact_broker_fullname",
id:"contact_user_name",
}).appendTo('.contact_user_name');
var input_button = $('<input>',{
name:"submit",
type:"submit",
value:"Send"
}).appendTo('#new_contact');
var full_name=name_filed.val();//I'm not sure that this should be here at all.
input_button.on('click',function(){
ajax_send_contact(full_name);
return false;
});
});
And here is the ajax_send_contact(full_name) function:
$.ajax({
url:'../some.php',
type:'post',
data:{name:full_name},
success: function (response){
if (response) {
$('#success').append('<span>All right.</span>');
}
else{
$('#errors').append('<span>Something went wrong.</span>');
}
},
error: function () {
$('#errors').append('<span>ERROR!</span>');
}
});
I've read that when adding dynamically element to HTML they're not included into the DOM, so how can i operate with them. How i can get the value of the input so once the user click the Submit button the value is sent to ajax function. And I'm not asking only for this particular case but for the whole logic as I'm missing something quite important.
Thank you.
I don't know where you read this but it's not true.
Adding elements to your page is DOM manipulation.
In fact there is a lot of DOM manipulation in your ready function.
DOM manipulations are costly, try to reduce them by grouping operations :
var formHtml = '';
formHtml += '<div class="contact-form">';
formHtml += '<form id="new_contact">';
formHtml += '<div class="contact_user_name">';
formHtml += '<input type="text" name="contact_broker_fullname" id="contact_user_name">';
formHtml += '</div>';
formHtml += '<input type="submit" name="submit" value="send">';
formHtml += '</form>';
formHtml += '</div>';
$('#add_contacts').append(formHtml); // Only 1 DOM manip.
There are errors in your code :
$('#add_contacts').append('<div class="contact-from"></div>');
...
var name_field = $('<input>',{
And then :
$('<form></form>',{id:'new_contact'}).appendTo('.contact-form');
...
var full_name=name_filed.val();
'contact-from' then 'contact-form'.
'name_field' then 'name_filed'.
In your code, you get the value of your input#contact_user_name right after you created the form,
that is to say before the user had any chance to input something in it.
You have to do this in your click handler.
Pretty simple, set the data with the value of the field right before firing the request:
data: { name: $('.contact_user_name input').val() }
And you can remove var full_name=name_filed.val(), it would only get the value the field had at the moment it was created, and apparently that variable wouldn't be in scope when you actually need it.
The rest of your code looks okay.

Categories

Resources