I have this while loop in PHP
<?php
while ($row = mysqli_fetch_assoc($getPosts)) {
$post_id = $row['post_id'];
echo "<td><a rel='$post_id' id='get_post_id'
onclick='active_del_modal()'>Delete</a></td>";
}
?>
In this loop, when we click on the "delete" link, the value of variable "$post_id" changes. I want to get the value of "$post_id" when it changes. I tried with this JS code
function active_del_modal() {
var x = document.getElementById("get_post_id").getAttribute("rel");
alert(x);
}
But it only gives me the last value of "$post_id". I want to get each value of "$post_id" when it changes and this value should be individual, not like this 23 46 545 545, etc. I don't want to use any framework like jQuery.
An ID must be unique in a document. So stop using static IDs in a loop.
Links go somewhere. Don't use a link if you aren't navigating. Use a button if you want something to click on to trigger JS. Apply CSS if you don't like the default appearance of a button.
A post ID is not a type of relationship. Don't abuse rel attributes. (Appropriate use would be something like <a href="page2.html" rel="next">) Use a data-* attribute if you need to associate custom data with an element.
Intrinsic event attributes have a bunch of gotchas associated with them. Don't use them. Use addEventListener and friends instead.
function active_del_modal(event) {
const button = event.target;
const id = button.dataset.postId;
console.log({
id
});
}
document.querySelector("#delete-buttons").addEventListener("click", active_del_modal);
button {
border: none;
background: none;
colour: blue;
cursor: pointer;
}
button:hover {
text-decoration: underline;
}
<ul id="delete-buttons">
<li><button type="button" data-post-id="$post_id">Delete</button></li>
<li><button type="button" data-post-id="foo">Delete</button></li>
<li><button type="button" data-post-id="bar">Delete</button></li>
</ul>
Method 1 - minimum change
onclick='active_del_modal(this)'
and you can use
function active_del_modal(link) {
var x = link.getAttribute("rel");
alert(x);
}
Method 2 - better:
window.addEventListener("load",function() {
document.querySeletor("table").addEventListener("click",function(e) {
const tgt = e.target, rel = tgt.getAttribute("rel");
if (rel) alert(rel);
})
})
I recommend using data-attributes instead of rel:
If you change id to class, you can do this
window.addEventListener("load",function() {
document.querySeletor("table").addEventListener("click",function(e) {
const tgt = e.target;
if (tgt.classList.contains("get_post_id")) {
const id = tgt.dataset.id;
console.log(id);
}
})
})
using
echo "<td><a data-id='$post_id' class='get_post_id'>Delete</a></td>";
LASTLY if the link is supposed to delete the row, you can do
window.addEventListener("load",function() {
document.querySeletor("table").addEventListener("click",function(e) {
const tgt = e.target;
if (tgt.classList.contains("delete")) {
tgt.closest("tr").remove();
}
})
})
using
echo "<td><button type="button" class='delete'>Delete</button></td>";
Related
This question already has answers here:
info on javascript document.createElement()
(4 answers)
Closed 12 months ago.
I want to display a new input field with a new name everytime a button is clicked. how do I achieve that? I found solutions to adding the input but none mentions adding a new name to it.
HTML:
Add a keyword
<div id="fieldContainer"></div>
Javascript:
function addKeywordFields() {
var mydiv = document.getElementById("fieldContainer");
mydiv.appendChild(document.createTextNode("<input type='text' name=''>"))
}
You should not use document.createTextNode to create an input. This will only create a text element with content specified inside it.
Instead you should create an input using document.createElement('input') and specify its type and name.
Since you need a dynamic name, you have to integrate a dynamic name generation logic. Here I used (new Date()).toISOString() since this will e unique each time. Instead you have to use your own logic.
Working Fiddle
function addKeywordFields() {
var mydiv = document.getElementById("fieldContainer");
const input = document.createElement('input');
input.type = 'text';
input.name = (new Date()).toISOString(); // Some dynamic name logic
mydiv.appendChild(input);
}
<a onclick="addKeywordFields()">Add a keyword</a>
<div id="fieldContainer"></div>
There's a ton of DOM methods designed to create, destroy, move, etc. There's generally three ways to create a DOM element programmatically:
clone an element with .cloneNode() and .append()
parse a string that represents HTML (aka htmlString) use .insertAdjacentHTML() instead of .innerHTML
create an element with .createElement() and .append()
Assigning attributes/properties to an element can be done initially with .setAttribute() once an attribute has been assigned to an element, it is technically a property. This distinction between attribute and property is blurry because methods seem to work 100% as does assigning properties. jQuery is not so flexible in this instance, .attr() and .prop() have silently failed on me when I forget about attribute/property quirks.
I rarely use methods to assign attributes, properties are terse and simple to use, here's a few common ones:
obj.id = "ID", obj.className = "CLASS", obj.name = "NAME"❉,
obj.type = "TEXT", obj.dataset.* = "*"
❉This is the property you use to set/get name attribute
I always add a <form> if there's multiple form controls. There are special features and terse syntax if you use interfaces like HTMLFormElement✤ and HTMLFormControlsCollection✼. Moreover having a <form> you can use it to listen for events for everything within it❉ and also take advantage of special form events like "input", "change", "submit", etc.
HTMLFormElement.elements collects all form controls (listed below)
<button>, <fieldset>, <input>, <object>, <output>, <select>, <textarea>.
From the .elements property, any form control can be referenced by #id or [name]. If there is a group of form controls that share a [name] they can be collected into a HTMLCollection.
References
HTMLFormElement✤
HTMLFormControlsCollection✼
Events
Event Delegation❉
Further details are commented in example below
// Reference the form (see HTMLFormElement)
const UI = document.forms.UI;
// Register form to click event
UI.addEventListener('click', makeInput);
// Define a counter outside of function
let dataID = 0;
// Pass Event Object
function makeInput(e) {
/*
"this" is the form
.elements property is a collection of all form controls
(see HTMLFormsCollection)
*/
const io = this.elements;
// Event.target points to the tag user clicked
const clk = e.target;
/*
This is the fieldset containing the inputs it's in bracket notation
instead of dot notation because it's a hyphenated property
*/
const grp = io['form-group'];
// This is the static input
const inp = io.data;
// if the clicked tag is a button...
if (clk.matches('button')) {
// ...increment the counter
dataID++;
/*
This switch() delegates what to do by the clicked button's [name].
Each case is a different way to create an element and assign a unique
[name] by concatenating the "data" with the current number of dataID
*/
switch (clk.name) {
case 'clone':
const copy = inp.cloneNode(true);
copy.name = 'data' + dataID;
grp.append(copy);
break;
case 'html':
const htmlStr = `
<input name="data${dataID}">`;
grp.insertAdjacentHTML('beforeEnd', htmlStr);
break;
case 'create':
const tag = document.createElement('input');
tag.name = 'data' + dataID;
grp.append(tag);
break;
default:
break;
}
}
};
form {
display: flex;
}
fieldset {
display: inline-flex;
flex-direction: column;
justify-content: flex-startd;
max-width: 90%;
}
input,
button {
display: inline-block;
width: 80px;
margin-bottom: 4px;
}
input {
width: 150px;
}
button {
cursor: pointer;
}
<form id='UI'>
<fieldset name='btn-group'>
<button name='clone' type='button'>Clone Node</button>
<button name='html' type='button'>Parse htnlString</button>
<button name='create' type='button'>Create Element</button>
</fieldset>
<fieldset name='form-group'>
<input name='data'>
</fieldset>
</form>
^I would like to be able for the style to be enabled for only one at a time.
^I'm able to do this, which I don't want the user to be able to do.
So it's weirdly hard framing a question for what is possibly an easy solution. I basically have a list of build versions where I want the user to select one. When one of the versions are selected, it adds a border to the item to display that its clicked. However, with my code right now the user is able to select all 3 items and enable their CSS elements. I would like for the user to be able to only "activate" one item from the list.
HTML and CSS:
<ul class="listContents">
<li><p>Stable</p></li>
<li><p>Preview</p></li>
<li><p>LTS</p></li>
</ul>
<style>
.colorText {
background-color: #58a7ed;
color: white;
}
</style>
and the JS stuff:
const btn = document.querySelectorAll('.links');
for (let i = 0; i < btn.length; i++ ) {
btn[i].addEventListener("click", function() {
btn[i].classList.add('colorText')
})
}
I really hope I made myself clear, I feel like I'm failing my English trying to word this right lol.
You can also use a forEach loop, accessing the clicked link using event.target
const btns = document.querySelectorAll('.links');
btns.forEach(btn => {
btn.addEventListener('click', e => {
// remove any existing active links
btns.forEach(b => b.classList.remove('colorText'));
// activate the clicked link
e.target.classList.add('colorText');
})
});
.colorText {
background-color: #58a7ed;
color: white;
}
<ul class="listContents">
<li>
<p>Stable</p>
</li>
<li>
<p>Preview</p>
</li>
<li>
<p>LTS</p>
</li>
</ul>
Just before you add the colorText class to the desired item, we can remove colorText from ALL of them, ensuring that only 1 at a time gets the class.
// the rest is the same...
btn[i].addEventListener("click", function() {
// remove it from all:
btn.forEach(function(item) {
item.classList.remove('colorText');
});
// add it back to the desired one
btn[i].classList.add('colorText')
})
you can also use simple for of
const btn = document.querySelectorAll(".links");
for (let bt of btn) {
bt.addEventListener("click", (e) => {
btn.forEach((b) => b.classList.remove("colorText"));
e.target.classList.add("colorText");
});
}
const list = document.getElementById('list')
const addtodo = document.getElementById('addtodo')
//const items = document.querySelector('.item')
const deleteItem = document.querySelector('.delete')
addtodo.addEventListener('keypress', submitTodo)
function submitTodo(event) {
if (event.keyCode == 13) {
event.preventDefault()
let value = addtodo.value
let li = document.createElement('li')
li.innerHTML = `
<img class="unchecked" src="icon/unchecked.svg" />
${value}
<img class="delete" src="icon/icons8-multiply-26.png" /> `
list.appendChild(li)
}
}
deleteItem.addEventListener('click', items)
function items(item) {
if (item.target.classList.contains('delete')) {
item.target.parentElement.remove()
}
}
The code above only allows me to delete one item and its the first one on the list
I try to solve it on my own but couldn't any idea whats wrong
When deleteItem.addEventListener('click', items) is ran, it only attaches the eventListener to the elements currently on the DOM - the ones you create dynamically will not have this eventListener
You can use 'event delegation' instead to listen for clicks, and filter theses clicks based on if the click was coming from the correct element
You can read more about event delegation from davidwalsh's blog and this StackOverflow answer
document.addEventListener('click', function(e) => {
if(e.target && e.target.classList.includes('delete')){
e.target.parentElement.remove()
}
});
You could also make use of the elements onclick attribute, and pass this in the parameter of the function call - this way you can access the HTML Element directly from the parameter; this also avoids having to have an eventListener, or using an if to check if it's the correct class / ID
// Add the function to the onclick attribute of the img
<img class="delete" onclick="deleteItem(this)" src="demo.png" />
// in this function, 'item' refers to the DOM Element that was clicked
function deleteItem (item) {
item.parentElement.remove();
}
This code will allow you to remove the first element on ul .
let list = document.getElementById("list"); // ul element
let remove = document.getElementById("remove"); // remove button
// on double click event
remove.onclick = () => {
// remove the first child from the list
list.removeChild(list.firstChild);
}
<ul id="list">
<li>One</li>
<li>Two</li>
<li>three</li>
</ul>
<input type="button" id="remove" value="Remove First"></input>
I am trying to remove the style of my a href background. The issue is when I concatenate dynamic id with selector then it don't work. But when I use complete name of selector, then it works.
I know you can mark my question as duplicate like here but they are not working for me. Please correct me.
What Works:
$("a").click(function(event)
{
var id = event.target.id;
$('#chatIdStyle4').removeAttr("style");
});
What Didn't:
$("a").click(function(event)
{
var id = event.target.id;
$('#chatIdStyle'+id).removeAttr("style");
});
OR
$("a").click(function(event) {
//alert(event.target.id);
var iddds = event.target.id;
$('#chatIdStyle["'+ iddds + '"]').removeAttr("style");
});
NOTE: var id contains the dynamic id of event fired.
EDIT as asked:
Below is my HTML+PHP code. So, what it does is actually creates 4 dynamic a href with dynamic id. What I
want is when a specific a href gets clicked then it should remove previous a href background and
add background to the clicked a href.
<?php
$color = false;
$PID = 4;
for($i=0;$i<4;$i++)
{
?>
<a <?php if($color==true)
{
?> style="background-color: #E6E6E6;" <?php
}
$color=false;
?>
id="chatIdStyle<?php echo $PID; ?>"
href="#">
</a>
<?php
}
?>
I suggest using CSS solution instead of jQuery:
a { background: none; }
a:active { background: #E6E6E6; }
The second line will set the background for the last clicked a element.
About the :active pseudo class: https://www.w3schools.com/cssref/sel_active.asp
I want to click on an element to toggle a class being referenced on a completely unrelated element (not a child, parent or sibling)
For example, initially the code would look like this
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
When the user clicks the element with the id button the HTML would change to look like this (the class "open" is referenced on element with "navigation" already referenced":
<a id="button">Button</a>
<div class="navigation open">
Foo
</div>
The user should be able to toggle the class by clicking the element with the id button.
I would like to use pure javascript to achieve this effect.
You could attach click event to the button with id button then on click select the element with class navigation using getElementsByClassName() (ti will return list of nodes) then select the first one using [0] then use toggle() :
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
Hope this helps.
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
.open{
background-color: green;
color: white;
}
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
You don't really need javascript. Checkboxes work great at storing on/off state. You just need to get a little crafty with the CSS to use it elsewhere. Here is an example:
label.divcheck { color:blue; text-decoration:underline; }
input.divcheck { display:none; }
input.divcheck + div { display:none; }
input.divcheck:checked + div { display:block;}
<label class="divcheck" for="navigation">Button Nav</label>
<label class="divcheck" for="other">Button Other</label>
<input type="checkbox" class="divcheck" id="navigation"/>
<div class="navigation">
Foo
</div>
<input type="checkbox" class="divcheck" id="other"/>
<div class="navigation">
Other
</div>
Multiple elements with class navigation
navigation is a class, so I assume there is more than one element you would like to give class open on click on element with id button. Do it that way:
function toggleNavigation(element) {
element.classList.toggle('open');
}
document.getElementById('button').addEventListener('click', function() {
Array.from(document.getElementsByClassName('navigation')).forEach(toggleNavigation);
});
.navigation {
background-color: lightgreen;
}
.navigation.open {
background-color: lightblue;
}
<a id="button">Button</a>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
Single element with class or id navigation
If it is otherwise (i.e., there is only one element with class navigation, in which case it should be an id, not a class) you can replace above JavaScript to:
document.getElementById('button').addEventListener('click', function() {
document.getElementsByClassName('navigation')[0].classList.toggle('open');
});
or if you will change navigation to be an id:
document.getElementById('button').addEventListener('click', function() {
document.getElementById('navigation').classList.toggle('open');
});
You need to add event handlers. This can be done by simple setting the onClick property on the Element object:
document.getElementById('button').onClick = function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
};
However, it's preferable that you use addEventListener so multiple event listeners can be added to the same element:
document.getElementById('button').addEventListener('click', function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
}, false);
EDIT: It's also better to cache your element references in variables like so:
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.className += 'open';
}, false);
EDIT2: as in Zakaria's answer, you may want to use classList.add(x) instead of className += x. It's more in line with how jQuery's things work. However, be aware that classList is not supported in older versions of IE.
EDIT3: Here's a final version using classList.toggle
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.classList.toggle('open');
}, false);
And here's a quick replacement for classList using className instead:
function classList(elem) {
var cl = {
add: function (clas) {
elem.className += clas;
},
remove: function (clas) {
elem.className = elem.className.replace(clas, '');
},
toggle: function (clas) {
if (elem.className.indexOf(clas) > -1) {
cl.remove(clas);
} else {
cl.add(clas);
}
}
};
return cl;
}
// usage
classList(nav).add('open');
classList(nav).toggle('open');
Try this:
document.querySelector('div.navigation').classList.toggle('open');
This will work if you only have one div element that has the class navigation. It would be better to give it an id, for example id=navigation