Remove dynamically registered events at a later point - javascript

I have this code that registers an event to an array of breakpoints:
var breaks = ["(min-width: 800px)","(min-width: 300px)"];
var breakChange = function(mq) {
console.log(mq);
}
for ( i = 0; i < breaks.length; i++ ) {
var mq = window.matchMedia(bG.breaks[i]);
mq.addListener(breakChange);
}
It works great, but I want to be able to remove the listeners from these breaks at a later point. Does anyone know what would be the best way to go about removing event listeners registered dynamically at a later point?

Related

Use Event Handler Instead of onClick to Fire API Function

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.

Event target should be anchor but is image instead

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]);
}

specific function in Javascript

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.

Javascript Onclick vs Onmousedown Race Condition

I have a SUBMIT and SAVE button for a form that are by default listening for Onclick events.
When the form is SUBMITTED OR SAVED - the page resets the scroll position to the TOP of the page.
Recently the users of the applications have requested that the page stay at the bottom of the page where the buttons are located for only a subset of forms.
(These buttons are used across hundreds of other forms so I cannot change the reset of the scrolling globally.)
So the solution that I am trying to implement involves a couple hidden input fields and a few event listeners.
I have added an onmousedown event for these buttons, like so -
// Submit and Save button listeners
var globalButtons;
if (v_doc.getElementsByClassName) {
globalButtons = v_doc.getElementsByClassName('globalbuttons');
}
// Internet Explorer does not support getElementsByClassName - therefore implement our own version of it here
else {
globalButtons = [];
var myclass = new RegExp('\\b'+'globalbuttons'+'\\b');
var elem = v_doc.body.getElementsByTagName("input");
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) {
globalButtons.push(elem[i]);
}
}
}
for (var gb = 0; gb < globalButtons.length; gb++) {
if (globalButtons[gb].name == 'methodToCall.route' ||
globalButtons[gb].name == 'methodToCall.save') {
if(globalButtons[gb].addEventListener) { //all browsers except IE before version 9
globalButtons[gb].addEventListener("mousedown", function(){flagSpecialScrollOnRefresh()},false);
}
else {
if(globalButtons[gb].attachEvent) { //IE before version 9
globalButtons[gb].attachEvent("onmousedown",function(){flagSpecialScrollOnRefresh()});
}
}
}
else { continue; }
}
This code is located in a function called attachButtonListeners
Next, I defined my handler like so and placed it into another function that gets called each time my page is being loaded -
function checkSpecialScrollCase() {
var spfrm = getPortlet();
var sp_doc = spfrm.contentDocument ? spfrm.contentDocument: spfrm.contentWindow.document;
var specialScrollExists = sp_doc.getElementById(docTypeButton).value;
if (specialScrollExists == "YES") {
sp_doc.getElementById(docTypeButton).value = 'NO';
}
// else - nothing to do in this case
}
docTypeButton = REQS_BUTTONS
And it references the following element at the bottom of my JSP page -
<input type="hidden" id="REQS_BUTTONS" value="NO"/>
<a name="anchorREQS"></a>
Notice the anchor tag. Eventually, I need to add the location.hash call into my handler so that I scroll to this location. That part is irrelevant at this point and here is why.
Problem -
My flagSpecialScrollOnRefresh function is NOT setting the value to YES when it should be.
I believe my onClick event is happening too fast for my onmousedown event from happening.
Evidence -
If I place an alert statement like so -
function flagSpecialScrollOnRefresh() {
var scfrm = getPortlet();
var sc_doc = scfrm.contentDocument ? scfrm.contentDocument: scfrm.contentWindow.document;
alert("BLAH!");
sc_doc.getElementById(docTypeButton).value = "YES";
}
And then I examine the element using Firebug - the value is getting SET!
Once I take out the alert - no go!
How do I ensure that my mousedown event gets executed first? Or is this even the problem here????
mousedown is part of a click event.
Whatever you are doing with click events now should be moved to the submit event on the form. That way you can use mousedown, mouseover, or even click on the buttons to do whatever you want.

Set an HTML5 Video to PAUSE when video player is out of view

I'd like to do this with javascript. I'm building a presentation using Hakim El Hattab's Reveal.js as a foundation.
The way Reveal.js works is the current slide you are viewing has a class of .present, any previous slides have a class of .past, and any slides yet to come into view have a class of .future.
I would like it to automatically pause any video that is inside a slide set to .past or .future.
How should I go about this?
Thanks in advance!
************UPDATE**************
so thanks to some direction i got over on the css-tricks forums i was able to get it working on a single video using getElementById.
below is the javascript i'm using to add the .past and .future classes and simultaneously pause a video.
if( i < index ) {
// Any element previous to index is given the 'past' class
slide.setAttribute('class', 'past');
document.getElementById('vid').pause();
}
else if( i > index ) {
// Any element subsequent to index is given the 'future' class
slide.setAttribute('class', 'future');
document.getElementById('vid').pause();
}
the issue that i'm having now is how would i apply it to a tag name (ie: video) or possibly a class.
Now that you posted your code, it makes it easier to fix:
if( i < index ) {
// Any element previous to index is given the 'past' class
slide.setAttribute('class', 'past');
var vids = document.getElementsByClassName("past");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
}
else if( i > index ) {
// Any element subsequent to index is given the 'future' class
slide.setAttribute('class', 'future');
var vids = document.getElementsByClassName("future");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
}
See if that helps. If it doesn't, are you using a modern and standards-compliant browser? getElementsByClassName() is a relatively new feature. It works in the latest version of Chrome for me.
I don't know if setTimeout would work here but you could try the following:
function PauseVids() {
var vids = document.getElementsByClassName("past");
var vids2 = document.getElementsByClassName("future");
for (var i = 0; i < vids.length; i++) {
vids[i].pause();
}
for (var i = 0; i < vids2.length; i++) {
vids2[i].pause();
}
}
// Within onLoad or $(document).ready()
setTimeout("PauseVids()", 1000);
Tell me if that works.
#petschekr :guess this won't work, because classname past future is not only set to videoelements?!
i have no idea how reveals work and what kind of player you are using! but my way would be sth like:
there is only one file with the present class, right (current Slide)
a) define sth like a onChange function (for example on every button which changes pages + keypresses)
b) trigger that function before you switch pages
function onChange(){
var currentSlice = document.getElementByClassName('present') //get current html elemen
var videoObjects = currentSlice.getElementsByTag('video') //get videoelements here html5 video
for each videoObj
videoObj.pause()
edit: pseudocode to get you an idea!

Categories

Resources