I'm trying to add an event of a button that is in a div.
HTML :
<template id="modele-panier" type="text/AhuntsicModele">
<div class="dialog-item">
<table>
<tr>
<td>
<img src={cheminImage} alt="">
</td>
<td>
<h2>Article : {libelleProduit}</h2>
<p>Qte : {qteProduit} prix : {prixProduit}$</p>
</td>
<div class="supp">
<td>
Supprimer
</td>
</div>
</tr>
</table>
</div>
</template>
Controler.js
document.addEventListener('click', function (e) {
if (e.target && e.target.matches('button')) {
controleur.ajouterPanier(e.target.id);
} else if (e.target && e.target.matches('#main')) {
controleur.loadCatalogue();
} else if (e.target && e.target.matches('#getBMW')) {
controleur.loadBMW();
} else if (e.target && e.target.matches('#getAudi')) {
controleur.loadAudi();
} else if (e.target && e.target.matches('#getMercedes')) {
controleur.loadMercedes();
} else if (e.target && e.target.matches('#icone_compte')) {
controleur.creationCompte();
} // THIS EVENT RIGHT HERE :
else if (event.target.matches('supp')) {
alert(e.target.id)
controleur.supprimerItem();
}
});
Im not able to add the event to the div class supp all the other are working fine since im not using a div class for the other ones.
Thanks
you could use this
const div = document.getElementsByClassName("supp");
else if (div[0]!=undefined) {
alert(e.target.id)
controleur.supprimerItem();
}
hope it helps
If I understand correctly, you'd like your controller logic to detect and process click events on the element with the supp class.
To achieve that with minimal changes to your code, you could do the following via the classList interface:
document.addEventListener('click', function(e) {
/* Existing code removed for bervity */
/* Use classList.contains method to check if target element has supp class */
if (event.target.classList.contains('supp')) {
alert(e.target.id)
controleur.supprimerItem();
}
});
<table>
<tr>
<td><img src="https://via.placeholder.com/150" alt=""></td>
<td>
<h2>Article : {libelleProduit}</h2>
<p>Qte : {qteProduit} prix : {prixProduit}$</p>
</td>
<div class="supp">
<td>Supprimer </td>
</div>
</tr>
</table>
I'm assuming that the click handler is targeting elements that are dynamically added to the DOM (which is why you're running the if/else if check inside of the click handler?) - another approach to this logic that might give you a bit more flexibility would be to query the DOM via a CSS-like selector and the querySelector() method:
document.addEventListener('click', function(e) {
/* Existing code removed for bervity */
/* Query document during click for first .supp relative to table */
const suppDiv = document.querySelector("table .supp")
if(suppDiv) {
alert('clicked .supp')
}
});
<table>
<tr>
<td><img src="https://via.placeholder.com/150" alt=""></td>
<td>
<h2>Article : {libelleProduit}</h2>
<p>Qte : {qteProduit} prix : {prixProduit}$</p>
</td>
<div class="supp">
<td>Supprimer </td>
</div>
</tr>
</table>
Hope that helps!
You are trying to use a function parameter event, which isn't called in your function. You named the parameter e in your function.
Also, .matches() checks if an element would normally be targeted based on a selector string. Which is what you would normally use to target elements with document.querySelector(). So supp should be changed to .supp.
So your code should work when you change it to:
} else if (e.target.matches('.supp')) {
controleur.supprimerItem();
}
Or even:
} else if (e.target && e.target.matches('.supp')) {
controleur.supprimerItem();
}
Like the rest of your if-statements.
Here is a snippet to show that this code should work as intended:
document.addEventListener("click", function (e) {
if (e.target && e.target.matches(".supp")) {
alert("It works");
}
});
.supp {
width: 100px;
height: 100px;
background-color: blue;
color: white;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
<div class="supp">Click me</div>
Related
I'm sorry, i'm very new to develop code. Now I'm doing some homework and want to do something outside of the textbook, but I'm failing ... :)
I created some simple html. Example:
<tr>
<td id="som1">5 + 3 =
<input id="a_som1" type="number" required>
</td>
<td>
<img src="goed.png" alt="goed" title="goed" id="i-s1g">
<img src="fout.png" alt="fout" title="fout" id="i-s1f">
</td>
And it ends with a button:
What I want is when you click on this button, the script checks your answer and either shows the "goed" or the "fout" image.
I hided the images with a css-stylesheet and this code:
img {
width: 35px;
display: none;
}
I tried the following as javascript, however, it doesn't work. (I know this code is probably very stupid, I just tried some things when searching the internet.) I hope someone can help me :):
Oh, and is it necessary to use $(document).ready(function() { . It was in my textbook, but I don't really know if it's necessary...
$(document).ready(function() {
$("#cont").click {
if ($("#a_som1").val() 8 ) {
show("#i-s1g")
}
else {
show("#i-s1f")
}
}
}
Thanks for helping!!
getting all the things i need 1:input 2:gIMAGE 3:fIMAGE & saving them in three variables..
putting eventListener on input of keypress then checking if the is enter,if is enter check if the number is equal to my answer("8").if yes show gimage and hide fimage,
if not hide gimage and show fimage
let input = document.getElementById("a_som1");
let gImg = document.getElementById("i-s1g");
let fImg = document.getElementById("i-s1f");
input.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
if (input.value == 8) {
gImg.style.display = "block"
fImg.style.display = "none"
} else {
fImg.style.display = "block"
gImg.style.display = "none"
}
}
});
img {
width: 35px;
display: none;
}
<tr>
<td id="som1">5 + 3 =
<input id="a_som1" type="number" required>
</td>
<td>
<img src="goed.png" alt="goed" title="goed" id="i-s1g">
<img src="fout.png" alt="fout" title="fout" id="i-s1f">
</td>
</tr>
I've been trying to find ways to trigger the dropdown (of class "update-message-button") using jquery when I click in the blank spaces of the parent <td> (of class "message-row") and even when clicked on its corresponding <td> (class "message-type-row").
I have attached my jquery code, but the dropdown doesn't get triggered.
Thanks in advance
$(".message-row").on("click", function () {
$(".update-message-button").trigger("click");
return false;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<tr>
<td class="message-row" scope="row">
<div class="dropdown dropleft">
<a class="update-message-button" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{this.message}}
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item update-message-id" href="#" data-toggle="modal" data-target="#exampleModal" data-id="{{this._id}}">Update</a>
<a class="dropdown-item" href="#">Remove</a>
</div>
</div>
</td>
<td class="message-type-row">
{{this.messageType}}
</td>
</tr>
Your script works,
BUT since .update-message-button is within .message-row
a click within .message-row triggers your trigger which in turn triggers the parent on('click'), and enters into an endless loop.
You might have to rethink your design, or use maybe: event.stopPropagation() to stop the execution after the first click.
Edit:
This works:
$(document).on("click", ".message-row",function () {
$(".update-message-button").triggerHandler("click");
});
https://codepen.io/ron7/pen/VweGVyb
It says you're new...so welcome to Stack!
If you don't use a JavaScript Framework at your workplace...jQuery is a perfectly fine approach
In looking at your HTML & explanation...it isn't really "that clear" what you are trying to accomplish. And, if I am correct, I feel your approach has some issues. That said...I will "try" to stay within the boundaries of what I believe you are asking (and try not to change it too much).
It "looks" like you want to...
Display a "dropdown" (of sorts) when the parent is 'clicked'
Manage the "update & remove" options when chosen
In anayzing the HTML you provide...you may also be wanting to notify other components of the users choice (so I added that too).
SIDE NOTES:
I "compressed" the CSS & HTML down a bit for you
Message...is your 'Record Class'
MessagePublisher...is your 'HTML Template Class'
SubscriptionController...is the 'Subscriber Class' (this is optional)
logger...logs to the console (handy...but also optional)
Cheers!
var logger = (function () {
return {
log: function () {
if (console) {
var args = Array.prototype.slice.call(arguments);
console.log.apply(console, args);
}
}
}
})();
function Message(id, messageType) {
this.id = id;
this.messageType = messageType;
}
function MessagePublisher(record) {
var _record = record,
_$message = null,
_$messageOptions = null,
_$messageType = null,
_$dropdown = null,
_$updater,
_$destroyer;
return {
dataBind: function (ele) {
// Elements
_$message = $(ele);
_$messageOptions = $('.message-options', _$message);
_$messageType = $('.message-type', _$message);
_$dropdown = $('.dropdown', _$messageOptions);
_$updater = $('.update-message', _$dropdown);
_$destroyer = $('.destroy-message', _$dropdown);
// Values
_$messageType.text(_record.messageType);
_$updater.attr('data-id', _record.id)
_$destroyer.attr('data-id', _record.id)
// Events
_$messageOptions.on('click', this.on.click.messageOptions);
_$destroyer.on('click', { publisher: this }, this.on.click.removeMessage);
_$updater.on('click', { publisher: this }, this.on.click.updateMessage);
},
on: {
click: {
messageOptions: function (e) {
e.preventDefault();
if (!_$dropdown.is(':visible')) {
_$dropdown.show();
}
},
removeMessage: function (e) {
e.preventDefault();
$(e.data.publisher).trigger('destroy::record', [_record])
},
updateMessage: function (e) {
e.preventDefault();
$(e.data.publisher).trigger('update::record', [_record])
}
}
}
};
}
function SubscriptionController() {
return {
on: {
destroy: function (e, record) {
logger.log('DESTROY', [record]);
},
update: function (e, record) {
logger.log('UPDATE', [record]);
}
}
};
}
$(document).ready(function () {
// Subscriber
window.subscriber = new SubscriptionController();
// Publishers
var $messages = $('.message');
$.each($messages, function (index, ele) {
var id = index+1;
var record = new Message(id, 'Awesome Message Type');
var controller = new MessagePublisher(record);
controller.dataBind(ele);
// Apply Subscriptions
$(controller).on('destroy::record', window.subscriber.on.destroy);
$(controller).on('update::record', window.subscriber.on.update);
});
});
table { width: 600px; }
table tbody tr.message { }
table tbody tr.message td { border: 1px solid #e3e2e1; padding: 5px; }
table tbody tr.message td { width: 50%; }
.message { }
.message .message-options { cursor: pointer; }
.message .message-options .dropdown { display: none; }
.message .message-options .dropdown a { display: block; }
.message .message-options .dropdown .sub-menu { }
.message .message-options .dropdown .sub-menu .menu-item { cursor: pointer; }
.message .message-type { }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody>
<tr class="message">
<td valign="top" class="message-options">
<div class="dropdown">
<a class="dropdown-message">Please Choose an Option</a>
<div class="sub-menu">
Update
Remove
</div>
</div>
</td>
<td valign="top" class="message-type">
</td>
</tr>
</tbody>
</table>
I am trying to get the coordinates of a shadow DOM table cell that may (or may-not) have overlay elements displayed in front of it. The clickable overlay elements may span over multiple cells so they will not necessarily be children of the cell I need the coordinates from.
I can't get the event to bubble through the table like I expect. I believe event re-targeting of the shadow DOM is preventing the event from ever hitting the cells when the event originates in the light DOM (I kinda think that this is the wrong approach anyways as the overlay element is not a child of the cell I want the coordinates from to begin with)
The "pointer-events: none;"property pretty much does what I want, however, I need the event to also trigger on the light DOM overlay element so I don't know if that is an option.
I am thinking it is a good idea to avoid attaching a listener to every cell for performance issues (in the final application there will be hundreds of cells)
I am using vanilla JavaScript
In the provided example, is it possible to get the correct coordinates of the underlying table cell when the overlying div grey is clicked?
class Custom_Grid extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'
});
this.shadowRoot.innerHTML = `
<style>
td {
height:50px; width:50px; border: 1px solid grey;
}
</style>
<table>
<tr>
<td id='x0y0'><slot name='x0y0'></slot></td>
<td id='x0y1'><slot name='x0y1'></slot></td>
<td id='x0y2'><slot name='x0y2'></slot></td>
</tr>
<tr>
<td id='x1y0'><slot name='x1y0'></slot></td>
<td id='x1y1'><slot name='x1y1'></slot></td>
<td id='x1y2'><slot name='x1y2'></slot></td>
</tr>
<tr>
<td id='x2y0'><slot name='x2y0'></slot></td>
<td id='x2y1'><slot name='x2y1'></slot></td>
<td id='x2y2'><slot name='x2y2'></slot></td>
</tr>
`;
}
connectedCallback() {
this.shadowRoot.addEventListener("click", (e) => {
if (e.target.matches('td'))
console.log(`Grid Cell: ${e.target.id}`)
});
}
}
window.customElements.define('custom-grid', Custom_Grid);
document.getElementById('grid_overlay').addEventListener("click", (e) => {
console.log("#overGrid Click")
});
#grid_overlay {
width: 100px;
height: 100px;
background-color: grey;
position: absolute;
/*pointer-events: none; <-- not an option?*/
}
<custom-grid>
<div slot='x1y0' id='grid_overlay'></div>
</custom-grid>
A solution is to hide the overlay element temporarily in order to get the covered element thanks to the elementFromPoint() method.
if ( e.target.id === 'grid_overlay' ) {
console.log( 'overlay click' )
e.target.hidden = true
var el = this.shadowRoot.elementFromPoint( e.x, e.y )
if (el.id)
console.log( 'under: ', el.id )
e.target.hidden = false
}
class Custom_Grid extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
td {
height:50px; width:50px; border: 1px solid grey;
}
</style>
<table>
<tr>
<td id='x0y0'><slot name='x0y0'></slot></td>
<td id='x0y1'><slot name='x0y1'></slot></td>
<td id='x0y2'><slot name='x0y2'></slot></td>
</tr>
<tr>
<td id='x1y0'><slot name='x1y0'></slot></td>
<td id='x1y1'><slot name='x1y1'></slot></td>
<td id='x1y2'><slot name='x1y2'></slot></td>
</tr>
<tr>
<td id='x2y0'><slot name='x2y0'></slot></td>
<td id='x2y1'><slot name='x2y1'></slot></td>
<td id='x2y2'><slot name='x2y2'></slot></td>
</tr>
`;
}
connectedCallback() {
this.shadowRoot.addEventListener("click", (e) => {
if (e.target.matches('td'))
console.log(`Grid Cell: ${e.target.id}`)
else if (e.target.id === 'grid_overlay' ) {
console.log( 'overlay click ' )
e.target.hidden = true
var el = this.shadowRoot.elementFromPoint( e.x, e.y )
if (el.id)
console.log( 'under: ', el.id )
e.target.hidden = false
}
});
}
}
window.customElements.define('custom-grid', Custom_Grid);
#grid_overlay {
width: 100px;
height: 100px;
background-color: grey;
position: absolute;
}
<custom-grid>
<div slot='x1y0' id='grid_overlay'></div>
</custom-grid>
My HTML:
<tr class="main">
<td class="dropdown">
<a href="#">
<div class="dropdown-image"></div>
</a>
</td>
<td class="from">from</td>
<td class="subject">subject</td>
<td class="received">received</td>
<td class="status">Quarantined</td>
<td class="action">
<a href="#">
<div class="dropdown-menu"></div>
</a>
</td>
</tr>
I am trying to target the .dropdown-menu to change it's background image once the .dropdown-image has been clicked.
My JavaScript:
$(function) {
$('.dropdown-image').click(function() {
var clicks = $(this).data('clicks');
var td = $(this).parent().parent();
var tr = $(this).parent().parent().parent();
if (clicks) {
td.closest('.action').child().child().css("background-image", "url(images/new-arrow.png)");
} else {
td.closest('.action').child().child().css("background-image", "url(images/new-arrow-blue.png)");
}
$(this).data("clicks", !clicks);
});
});
However, this doesn't work. How can I target the .dropdown-menu correctly?
You seem to be trying to use the .closest() method to find the sibling '.action' element, but that's not what .closest() does. As explained in the doco, it looks for a matching ancestor element. So you can get the tr element that the clicked div belongs to like this:
var tr = $(this).closest("tr");
And then you can find the dropdown-menu div that belongs in that tr using .find() method - which is like the opposite of .closest() in that it looks for a descendant:
tr.find(".dropdown-menu")
In other words, to find the related .dropdown-menu, navigate up to the tr with .closest() and then back down to the related div with .find().
$(function() {
$('.dropdown-image').click(function() {
var $this = $(this),
clicks = $this.data('clicks'),
$relatedDiv = $this.closest("tr").find(".dropdown-menu");
if (clicks) {
$relatedDiv.css("background-image", "url(images/new-arrow.png)");
} else {
$relatedDiv.css("background-image", "url(images/new-arrow-blue.png)");
}
$this.data("clicks", !clicks);
});
});
Note that I only call $(this) once, putting the result in a variable. This is more efficient.
Also, as has been pointed out in comments, you have two syntax errors:
the first line should be $(function() { (you have incorrect parentheses)
the third-last line is missing a " before the comma.
JS
$(function () {
$('.dropdown-image').click(function () {
var $relatedDiv = $(this).parents('tr.main').find('.dropdown-menu');
$relatedDiv.toggleClass('bg-image-new-arrow-blue');
$relatedDiv.toggleClass('bg-image-new-arrow');
});
});
css
.bg-image-new-arrow{
color: red;
font-size: 12px;
background: url(images/new-arrow.png) no-repeat;
}
.bg-image-new-arrow-blue{
color: blue;
font-size: 23px;
background: url(images/new-arrow-blue.png) no-repeat;
}
html
<table>
<tr class="main">
<td class="dropdown">
<a href="#">
<div class="dropdown-image">asasdasdd</div>
</a>
</td>
<td class="from">from</td>
<td class="subject">subject</td>
<td class="received">received</td>
<td class="status">Quarantined</td>
<td class="action">
<a href="#">
<div class="dropdown-menu bg-image-new-arrow-blue">DropDown menu</div>
</a>
</td>
</tr>
</table>
The related is code-pen is in this link
I need a pure Javascript (no jQuery) hover effect for HTML table columns.
I found this which supposedly contains a fix for Firefox yet it still looks broken to me.
I found this which works only for the first column.
Unfortunately, my Javascript skills are amateur at best, so my attempts to modify either of these turned out to be fruitless.
Is this possible? Any suggestions would be appreciated.
Here's a column-based approach. When the mouse enters/leaves a cell, find the corresponding <col/> by index and apply/remove the desired class:
(() => {
const myTable = document.getElementById("myTable");
const cols = myTable.querySelectorAll("col");
const events = {
mouseover: e => {
const t = e.target.closest("td");
if (t) {
const cellIndex = t.cellIndex;
for (let i = 0, n = cols.length; i < n; i++) {
cols[i].classList[i === cellIndex ? "add" : "remove"]("hovered");
}
}
},
mouseout: e => {
const t = e.target;
if (t.nodeName === "TD" && !t.contains(e.relatedTarget)) {
cols[t.cellIndex].classList.remove("hovered");
}
}
};
for (let event in events) {
myTable.addEventListener(event, events[event]);
}
})();
.hovered {
background-color: #FF0000;
}
<table id="myTable" cellspacing="0">
<col />
<col />
<col />
<tbody>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2
<span>nested</span>
</td>
<td>Col3</td>
</tr>
<tr>
<td>Col1</td>
<td>Col2</td>
<td>Col3</td>
</tr>
</tbody>
</table>
See also:
Element.classList
Node.Contains()
Element.Closest()
Here are your codes (+ demo):
var HOVER_CLASS = 'hovered';
var hovered;
table.addEventListener('mouseover', function (e) {
if (e.target.tagName.toLowerCase() == 'td') {
var index = e.target.cellIndex;
hovered && hovered.forEach(function (cell) {
cell.classList.remove(HOVER_CLASS);
});
hovered = Array.prototype.map.call(
table.rows,
function (row) {
var i = index;
while (!cell && i >= 0) {
var cell = row.cells[i];
i -= 1;
}
return cell;
}
);
hovered.forEach(function (cell) {
cell.classList.add(HOVER_CLASS);
});
}
}, true);
table.addEventListener('mouseout', function (e) {
hovered && hovered.forEach(function (cell) {
cell.classList.remove(HOVER_CLASS);
});
hovered = null;
}, true);
Best method I can think of is to give each <td> a class name that identifies the column it's in. i.e. "col1, col2, etc"
Then you can use the document.getElementsByClassName("colX") function to get an array of those <td>s, loop through the array and modify the style. Warning, this may not work in older browsers that don't have a getElementsByClassName function, but there are workarounds you can find easily for that. The best of which would be to use jQuery, not sure why you're against it.
You create a class in css
.HoverTabla > tbody > tr:hover,
.HoverTabla > tbody > tr:focus {
background-color: #42C6F7;
}
and then you call it from the table in the html
<table class="table HoverTabla" id="tbl_Plan">
<thead>
<tr>
<th>Tipo de plan</th>
<th>Tiempo en días</th>
<th>Max. Usuario</th>
<th>Max. Capacidad</th>
<th>Max. Casos</th>
<th>Valor plan</th>
<th></th>
</tr>
</thead>
</table>
CSS-only answer I found after a little bit of googling: https://css-tricks.com/simple-css-row-column-highlighting/
Each cell (<td>) in the table is given some padding through pseudo elements, which is used to create the hover effect. To make sure the hover effect doesn't extend further than the table itself, an overflow: hidden is used.
The sub-title in the article summarizes it all: "The trick is using huge pseudo elements on the <td>s, hidden by the table overflow"
Try
<td onMouseOver="this.bgColor='yellow';" onMouseOut="this.bgColor='white';">
This will work, no javascript needed. So it should work even when people turn javascript off.
Jfiddle: http://jsfiddle.net/vJacZ/
Html:
<table>
<tr>
<td class="column1">
Column1
</td>
<td class="column2">
Column2
</td>
</tr>
</table>
Css:
.column1{
color:black;
}
.column1:hover{
color:red;
}
.column2{
color:black;
}
.column2:hover{
color:green;
}