I am working on a dialog script in Vanilla JS. I ran into a problem with the click event on the video image. Even tough the image is surrounded with an anchor tag it shows the image as the event.target on the "trigger-dialog-open" event.
Here is the HMTL:
<a class="trigger-dialog--open thumbnail" data-dialog-id="dialog-video" href="javascript:;">
<figure>
<img src="http://i.ytimg.com/vi/id/sddefault.jpg" alt="" />
</figure>
</a>
And this is the event in JS:
var openTriggers = document.getElementsByClassName('trigger-dialog--open');
for (var i = 0; i < openTriggers.length; i++) {
openTriggers[i].addEventListener("click", function (event) {
this.openDialog(event.target.getAttribute('data-dialog-id'));
}.bind(this), false);
}
The event handler wants to know the dialog-id from the anchors data attribute. It can't be found because it thinks the image is the event.target, not the actual anchor. How can I correct this? Thanks!
Use event.currentTarget. The event.target is supposed to be the img element since that is what the user has clicked on. The click then bubbles up through the image's containers. event.currentTarget gives you the element that the click handler was actually bound to.
(Or if you didn't bind this to some other object you could use this within the click handler and it should also be the current target.)
I have a few questions is the var openTriggers supposed to be a part of a module hash? Because if it's global then you don't use a this, you only add a this, if it's referencing a variable that the function is also contained in. For example:
var aThing = {
openTriggers: document.getElementsByClassName('trigger-dialog--open'),
openModal: null,
openDialog: function(clickedThingAttr){
if(this.openModal !== null){
this.openModal.style.display = 'none';
}else{
this.openModal = document.getElementById(clickedThingAttr);
}
this.openModal = document.getElementById(clickedThingAttr);
this.openModal.style.display = 'block';
},
setEventListenersNStuff: function(){
for (var i = 0, n = this.openTriggers.length;i < n; i++) {
this.openTriggers[i].addEventListener("click", function (event) {
this.openDialog(event.target.getAttribute('data-dialog-id'));
});
};
}
};//end of aThing hash object
aThing.setEventListenersNStuff();
There are a few issues here:
1. why are you using .bind I think that is a jQuery thing, you want to pass a string to another function when an object is clicked, there no need for binding at all.
2. Also make sure that if you want to do something like open a modal, there is no need to call another method unless it's kinda complex.
3. What about other potential dialogs, it seems that when a .trigger-dialog--open is clicked you're just showing that one one modal with the embedded id, but what about others? Make sure all modals are closed before you open a new one, unless you want to have like 10 modals are open.
A thing to note: I added the line var i = 0, n = openTriggers.length;i < n; i++, now in this case it's silly optimization, and I heard for modern browsers this doesn't apply, but to explain why I added it, is because i < openTriggers.length would count and integrate the array N times. (This may be an outdated optmiziation).
If you meant global
Below I added a different set of code, just in case you meant that var openTriggers is global, kinda like you wrote above. Also I used querySelectorAll for this which is like jQuery's $('.thing') selector.
anyhoo, I also added
var openTriggers = document.querySelectorAll('.trigger-dialog--open');
var n = openTriggers.length;
function openDialog(ddId){
for (var i = 0;i < n; i++) {
openTriggers[i].style.display = 'none';
};
document.getElementById(ddId).style.display = 'block';
};
for (var i = 0;i < n; i++) {
openTriggers[i].addEventListener("click", function (event) {
openDialog(event.target.getAttribute('data-dialog-id'));
});
}
}
So for the question of hiding already open modals I would suggest you could either cache the open Dialog within a module, or you could toggle a class, which would be less efficient since it would require an extra DOM search. Additionally you could add a if this.openModal.id === clickedThingAttr to hide if open, that way you got a toggle feature.
Anyways I suggest you read up on this stuff, if you want to use plain JS but would like the features of jQuery: http://blog.romanliutikov.com/post/63383858003/how-to-forget-about-jquery-and-start-using-native
Thank you for your time.
You can use a closure
var openTriggers = document.getElementsByClassName('trigger-dialog--open');
for (var i = 0; i < this.openTriggers.length; i++) {
(function(element) {
element.addEventListener("click", function (event) {
element.openDialog(event.target.getAttribute('data-dialog-id'));
}, false)
})(openTriggers[i]);
}
Related
Apologies if my problem sounds trivial to JS experts.
I've created an image slider (carousel) and, while loading thumbnails, I'm trying to create a reference to a full-size image, so that when a thumbnail is clicked - the image opens in another div.
The relevant code within window.onload handler is:
for (var i = 0; i < numImages; ++i) {
var image = images[i],
frame = document.createElement('div');
frame.className = 'pictureFrame';
/* some styling skipped */
carousel.insertBefore(frame, image);
frame.appendChild(image);
} /* for */
My first attempt was to add "onclick" at the end of the for loop:
frame.onclick= function () {
var largeImage = document.getElementById('largeImage');
largeImage.style.display = 'block';
largeImage.style.width=200+"px";
largeImage.style.height=200+"px";
var url=largeImage.getAttribute('src');
document.getElementById('slides').style.display = 'block';
document.getElementById("slides").innerHTML="<img src='url' />";
}
However, this may only work with hard-coded ids (e.g. 'largeImage').
Ideally, I need to pass image.src as a parameter but this (frame.onclick= function (image.src)) will not work.
My next thought was to put all logic of getting image.src to a separate function and displaying it with frame.onclick= myFunction;
However, I came over an example:
<input type="button" value="Click me" id="elem">
<script>
elem.onclick = function(event) {
// show event type, element and coordinates of the click
alert(event.type + " at " + event.currentTarget);
alert("Coordinates: " + event.clientX + ":" + event.clientY);
};
</script>
And here it is above me to understand why in this example a handler can accept a parameter.
What would be a correct way of assigning an image to the onclick event? Or is there a better way of turning a thumbnail into href?
While it might not be the best way, you could place the full size image path as a data-attribute on your thumbnail.
<img id="thumbnail" src="thumbnailpath" data-fullSizeImage="fullSizePath">
Then on your onclick, you could access the thumbnail element and get it's data- attribute.
function onClick(event){
var fullSizePath = event.currentTarget.getAttribute("data-fullSizeImage");
//Do whatever you want with fullsizepath
}
Code is untested; but, something like that should work based on my experience.
data attributes are a very flexible custom attribute for developers to use. Essentially you start with "data-" and then append a name to represent the attribute. Here is the documententation link.
You can create a closure (that is, an anonymous function) and register it as an event handler to access variables from outside the event handler inside the event handler itself:
for (var i = 0; i < numImages; ++i) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + i);
});
}
However, this will not quite work, since the variable i is changed every time the loop increases it, and closures don't "capture" the current value, only the reference itself, so at the end i will be equal to numImages for each event listener.
If you're using ES6 you can overcome this by using let (or const) to prevent this behavior:
for (let i = 0; i < numImages; ++i) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + i);
});
}
If using ES6 is not an option, you can still accomplish this in ES5 and earlier by wrapping the inside of your loop in a function that takes i as a parameter, which makes sure each event handler references different variables, since these parameters are different variables for each iteration:
for (var i = 0; i < numImages; ++i) {
(function (index) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + index);
});
})(i); /* pass in i here, which will be assigned to the index parameter */
}
I have a simple checkbox.
<div class="myCheckBox"><label><input type="checkbox" checked><span class="label-text">My Label</span></label></div>
Note: The HTML is part of a stack that already has a unique ID assigned to it (referenced the the JS as %id%.
I want to connect it to a javascript function. I know I can use onClick in the HTML to achieve this, but in this use case I need an event handler in my javascript to call (correct term?) the function.
My JS is
$(document).ready(function() {
var stack = $('%id%'),
checkbox = $('.myCheckbox',stack);
function filterCheck(%id=filterName%, %id=values%) {
var sheet = mainViz.getWorkbook().getActiveSheet();
var updateType;
if(checkbox.is(":checked")) {
updateType = "ADD";
} else {
updateType = "REMOVE";
}
worksheetArray = sheet.getWorksheets();
for (var i = 0; i < worksheetArray.length; i++) {
worksheetArray[i].applyFilterAsync(filterName, values, updateType);
}
}
}
checkbox.click(function(e) {
}
});
The event handler (I assume) goes after the checkbox.click(function(e) { ...but I am at a moment of clueless loss. Help?
I could see one issue with the code.
var stack = $('%id%'),
checkbox = $('.myCheckbox',stack);
You are not using # to reference id of element. Correct way should be either escaping the special characters
var stack = $('#\\%id\\%')
or by wrapping up dom object with jQuery Wrapper
var stack = $(document.getElementById('%id%'))
Both will help to find the stack which you have used as context below
$('.myCheckbox',stack);
event handler should work fine as given.
I have a function took on a tutorial, it works fine with one only element but I want to use it with some elements and I do not know enough about Javascript to do so.
This is my function :
var elements = document.getElementsByClassName('boules');
for (var i = 0; i < elements.length; i++) {
gameAccel(elements[i]);
}
function gameAccel(sphere) {
var x=20,y=300,vx=0,vy=0,ax=0,ay=0;
if(window.DeviceMotionEvent!=undefined){
window.ondevicemotion=function(e){
ax=event.accelerationIncludingGravity.x*3;
ay=event.accelerationIncludingGravity.y*3;
}
monInterval = setInterval(function(){
var landscapeOrientation=window.innerWidth/window.innerHeight>1;
if(landscapeOrientation){
vx=vx+ay;
vy=vy+ax;
}else{
vy=vy-ay;
vx=vx+ax;
}
vx=vx*0.98;
vy=vy*0.98;
y=parseInt(y+vy/50);
x=parseInt(x+vx/50);
boundingBoxCheck();
sphere.style.top=y+"px";
sphere.style.left=x+"px";
},25);
}
function boundingBoxCheck(){
if(x<0){x=0;vx=-vx;}
if(y<0){y=0;vy=-vy;}
if(x>document.documentElement.clientWidth-40){
x=document.documentElement.clientWidth-40;
vx=-vx;
}
if(y>document.documentElement.clientHeight-40){
y=document.documentElement.clientHeight-40;
vy=-vy;
}
}
}
I have one element with "boules" class, it works, if I have several elements with "boules" class it doesn't works.
This function is used on mobile device with gyroscope. (this is the basic example http://www.albertosarullo.com/demos/accelerometer/).
Someone can explain me why and how I can correct that ?
Thanks a lot.
You are overwriting window.ondevicemotion and monInterval every time you call the function. Only the last handler will be triggered. Instead, use addEventListener to attach multiple handlers and a local variable.
You have overwrites window.ondevicemotion handler in every loop. It must works only for last handler.
I'm new to programming and was wondering how to make a customized alert that shows the id or class name of the object when I click on it. My site has a picture of 8 different animals, and I want it so that every time I click on one of the animals there's an alert with "This is a (animal's name)". Why won't my javascript code below work?
should i be using "this" instead of "parama"? i don't understand whether or not to have any parameters for my function clicky.
var images = new Array()
images[0] = "bison"
images[1] = "frog"
function clicky(parama){
for (entry in images){
if (parama.attributes["name"].value === images[entry]){
$(parama).onClick(alert("This is a" + parama.attributes["name"].value));
} else {
$(parama).onClick(alert("dang it");
}
}
}
using sort of a combination of both your answers, I figured out a way to do it with a lot less code than I originally had. Check it out! (images all had classes of "pic")
$('.pic').click(function(){
alert("This is a " + this.getAttribute('alt'))
});
I'd recommend to use the title or alt attribute on images instead of a JS array - that's more SEO friendly and semantic. Not to mention that alt is required on images to make your HTML valid - DEMO
var images = document.getElementsByTagName("img");
for ( var i = 0, count = images.length; i < count; i++ ) {
images[i].addEventListener("click", function() {
alert( this.getAttribute("alt") );
});
}
UPDATE
if you open to use jQuery - DEMO
$("img").on("click", function() {
alert( $(this).prop("alt") );
});
You can use .click() but it's recommended to use .on() instead to attach different kind of event listeners to elements. jQuery also provides a shorthand for getting the properties - .prop()
I want to make a script that disables hyperlinks and instead fires a function when one is clicked.
should work as
<a onclick="talk('http://google.com)'></a>
Is there a way to know when the wants to redirect and instead run "talk()" or display an alert window?
var anchors = document.getElementsByTagName('a');
for (var a = 0; a < anchors.length; a++){
anchors[a].href = "javascript:talk('" + anchors[a].href + "');";
}
Use some discretion though...
This solution uses (DOM Level 0) event handling instead of touching the href directly.
(function () {
var anchors = document.getElementsByTagName('a'),
i = anchors.length;
while (i--) {
anchors[i].onclick = function () {
talk(this.href);
return false;
};
}
}());
Edit: The benefit of this approach is it's much simpler to put the href back when you want to. Given an anchor tAnchor, you merely need to unset the onclick attribute:
tAnchor.onclick = null