I'm trying to get the focus method (touch, mouse or keyboard) on links setting a data-attribute.
$(function() {
var i,
r = document.getElementsByTagName("a")[0];
if ("ontouchstart" in window) {
document.addEventListener("touchstart", function(event) {
i = "touch";
}, true);
}
else {
document.addEventListener("mousedown", function(event) {
i = "mouse";
}, true);
}
document.addEventListener("keydown", function(event) {
i = "keyboard";
}, true);
})
The problem is that I only get results writing the last part in jQuery:
$("a").focus(function() {
$(this).attr("data-focus-method", i)
})
$("a").blur(function() {
$(this).removeAttr("data-focus-method")
})
And I want to write the whole code in plain JavaScript. I've tried the way below:
r.addEventListener("focus", function() {
r.setAttribute("data-focus-method", i);
});
r.addEventListener("blur", function() {
r.removeAttribute("data-focus-method");
});
But it doesn't work.
Can somebody help me please?
I suggest to use querySelectorAll method and use forEach to iterate the nodelist
document.querySelectorAll("a").forEach((link) => {
link.addEventListener("focus", function() {
this.setAttribute("data-focus-method", i);
});
link.addEventListener("blur", function() {
this.removeAttribute("data-focus-method");
});
});
I'm not sure why you're trying to override the i on method whenever a key is pressed on the keyboard. However, I'm assuming that's the desired effect since you don't mention it in your question.
That said, here's something to get you closer to your goal of a vanilla JS version of the code.
The answer uses the spread operator to convert the nodeList you get from getElementsByTagName to an array and then forEach() to loop through the array items. For each item, we add two event listeners. one for focus, and one for blur.
When focused, we add the attribute. When blurred we remove the attribute. I opted for set attribute and remove attribute, but you can also use dataset if you want.
To determine what i (the method) is, I used let and a ternary operator.
I'm still not sure why you want to override the method when a key is pressed on the keyboard so I left that. I can improve that if you let me know what the desired effect is.
let i = ("ontouchstart" in window) ? "touch" : "mouse";
document.addEventListener("keydown", () => {
i = "keyboard"
})
const links = [...document.getElementsByTagName("a")];
links.forEach(link => {
link.addEventListener("focus", () => {
link.setAttribute('data-focus-method', i);
});
link.addEventListener("blur", () => {
link.removeAttribute('data-focus-method');
})
})
My link 1
My link 2
My link 3
I got the solution adding:
var w;
for (w = 0; w < r.length; w++) {
r[w].addEventListener("focus", function() {
this.setAttribute("data-focus-method", i);
});
r[w].addEventListener("blur", function() {
this.removeAttribute("data-focus-method");
});
}
By the way, thanks for everyone who helped me!
Related
So I have the following jQuery code that I've built out that checks whether a on change event has been triggered on #rtk5 and then either removes or adds the 'required' attribute.
Works perfectly in jQuery:
// Make checkbox textboxes not required unless checked
$(document).ready(function() {
$('#rtk5').change(function() {
if ($('.rtk5ReqField').attr('required')) {
$('.rtk5ReqField').removeAttr('required');
}
else {
$('.rtk5ReqField').attr('required','required');
}
});
});
I would like to convert it to JavaScript with a function call, but I can't seem to figure out how to properly do it.
Error:
TypeError: rtk5req.getAttribute is not a function
Here is my attempt:
var rtk5req = document.getElementsByClassName('rtk5ReqField');
function rtk5Required() {
rtk5req.addEventListener('change', (e) => {
if (rtk5req.getAttribute('required')) {
rtk5req.removeAttribute('required');
} else {
rtk5req.getAttribute('required', 'required');
}
});
}
rtk5req.addEventListener('change', rtk5Required());
document.addEventListener('DOMContentLoaded', rtk5Required);
rtk5Required();
Updated code: Removed the repetitive change call
var rtk5req = document.getElementsByClassName('rtk5ReqField');
function rtk5Required() {
if (rtk5req.getAttribute('required')) {
rtk5req.removeAttribute('required');
} else {
rtk5req.getAttribute('required', 'required');
}
}
rtk5req.addEventListener('change', rtk5Required());
document.addEventListener('DOMContentLoaded', rtk5Required);
rtk5Required();
Updated code #2:
Thanks all for all the hard work, there's one small issue that I'm still experiencing and had to make some tweaking - When I uncheck the checkbox, it doesn't remove the required tag placed on rtk5Declaration from which it did in the jQuery.
var rtk5_selection = document.getElementById('rtk5');
document.addEventListener('DOMContentLoaded', () => {
rtk5_selection.addEventListener('change', () => {
if (rtk5_selection.getAttribute('required')) {
document.getElementById('rtk5Declaration').removeAttribute('required');
} else {
document.getElementById('rtk5Declaration').setAttribute('required', 'required');
}
});
});
Thanks so much all!
Since you only have one element you should be using its ID instead of its class, and avoiding the complication caused by document.getElementsByClassName returning a pseudo-array of elements instead of a single element.
NB: use setAttribute to change an attribute's value, or better yet (as shown in the code below) use the direct boolean property that mirrors the element's attribute.
document.addEventListener('DOMContentLoaded', () => {
const rtk_sel = document.getElementById('rtk5');
const rtk_dec = document.getElementById('rtk5Declaration');
rtk_sel.addEventListener('change', () => {
rtk_dec.required = !rtk_sel.checked;
});
});
Thanks all for the contribution, below is the working version which I have tweaked:
var rtk5_selection = document.getElementById('rtk5');
var rtk5declaration = document.getElementById('rtk5Declaration');
function rtd3Declaration() {
if (!rtk5_selection.checked) {
rtd3declaration.removeAttribute('required');
} else {
rtd3declaration.setAttribute('required', 'required');
}
}
rtk5_selection.addEventListener('change', rtd3Declaration);
document.addEventListener('DOMContentLoaded', rtd3Declaration);
rtd3Declaration();
I am an Apprentice and never worked with Javascript.
My Javascript function calls a popup. This works on the first button but doesn't work on all the following and since the application is constantly adding buttons(same class) I cannot hardcode. I guess ther will be a solution with JQuery...
("open") and ("openPopupUseExisting") are the two buttons.
<script type="text/javascript">
window.onload = function () {
document.getElementById('blackout').addEventListener('click', function () {
document.getElementById('popup').className = "";
document.getElementById('blackout').className = "";
document.getElementById('popupUseExisting').className = "";
}, false);
document.getElementsByClassName("open")[0].addEventListener('click', function () {
document.getElementById('popup').className = 'visable';
document.getElementById('blackout').className = 'visable';
}, false);
document.getElementsByClassName("openPopupUseExisting")[0].addEventListener('click', function () {
document.getElementById('popupUseExisting').className = 'visable';
document.getElementById('blackout').className = 'visable';
}, false);
document.getElementsByClassName("close")[0].addEventListener('click', function () {
document.getElementById('popup').className = "";
document.getElementById('blackout').className = "";
document.getElementById('popupUseExisting').className = "";
}, false);
};
</script>
document.getElementsByClassName("close")[0]
See that 0?
getElementsByClassName returns an array-like object. You are getting the first item off it.
Loop over it with a for loop.
Friend, you don't need to add an entire library just in order to bind dynamically added elements.
You can bind the document for click event, and then check if the clicked element is the one you want. It prevent dynamically added elements to be unbound, since it aims for the entire document.
document.addEventListener('click', function (e) {
if (e.target.classList.contains('blackout')) {
// your fancy magic with .blackout
} else if (e.target.classList.contains('open')) {
// your fancy magic with .open
}
}, false);
If you really want to use jQuery, as you ordered, it's quite simple, use the on method
$('.open').on('click', function(){
// your fancy magic with .open
});
I'm trying to find a way to detect changes to the element style but I haven't had much luck. The code below works on a new property I define like tempBgColor but I cannot override/shadow an existing property like color. I know jquery has a watch function, but it only detects changes from the jquery api but not directly changing the value of a style something like elem.style.color.
var e = document.getElementById('element');
e.style.__defineGetter__("color", function() {
return "A property";
});
e.style.__defineSetter__("color", function(val) {
alert("Setting " + val + "!");
});
Any pointers?
You should be able to do this with a MutationObserver - see demo (Webkit only), which is the new, shiny way of getting notified about changes in the DOM. The older, now deprecated, way was Mutation events.
Demo simply logs in the console the old and new values when the paragraph is clicked. Note that the old value will not be available if it was set via a non-inline CSS rule, but the change will still be detected.
HTML
<p id="observable" style="color: red">Lorem ipsum</p>
JavaScript
var MutationObserver = window.WebKitMutationObserver;
var target = document.querySelector('#observable');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log('old', mutation.oldValue);
console.log('new', mutation.target.style.cssText);
});
});
var config = { attributes: true, attributeOldValue: true }
observer.observe(target, config);
// click event to change colour of the thing we are observing
target.addEventListener('click', function(ev) {
observable.style.color = 'green';
return false;
}, false);
Credit to this blog post, for some of the code above.
With Chrome's Developer Tools open, you can find the element whose style's change you're interested in, right click it, select "Break on..." and "Attributes modifications".
here is a naive implementation using setTimeout with undescorejs.
The only way to find out which change was made is to iterate through the style object properties.
Here is the live example
$( function () {
var ele = document.getElementById('ele'),
oldStyle = {};
function checkEquality() {
style = _.clone(ele.style);
if (!_.isEqual(style, oldStyle)) {
console.log('Not equal');
oldStyle = _.clone(style);
} else {
console.log('Equal');
}
_.delay(checkEquality, 2000);
}
checkEquality();
$('a#add_prop').on('click', function () {
var props = $('#prop').val().replace(/ /g, '').split(':');
console.log(props);
$(ele).css(props[0], props[1]);
});
$('#prop').on('keydown', function (e) {
if (e.keyCode == 13) {
$('a#add_prop').trigger('click');
}
});
});
I have in Javascript:
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
}
How can I continue in jQuery like:
$(function() {
$(vst).'click': function() {
....
}
}
NO, like this instead
$(function() {
$(vst).click(function() {
....
});
});
There are other ways depending on your version of jquery library
regarding to this, your vst must need to be an object which allow you to click on it, and you assign a class or id to the object in order to trigger the function and runs the for...loop
correct me if I am wrong, cause this is what I get from your question.
$(function() {
$(vst).click(function() {
....
}
})
You can use any string as element selector param for jQuery.
Read the docs for more information.
http://api.jquery.com/click/
http://api.jquery.com/
You can pass a String in a variable to the $() just the way you want to do it.
For example you can do:
var id = 'banner';
var sel = '#'+id;
$(sel).doSomething(); //will select '#banner'
What's wrong is the syntax you are using when binding the click handler. This would usually work like:
$(sel).click(function(){
//here goes what you want to do in the handler
});
See the docs for .click()
Your syntax is wrong, but other than that you will have no problem with that. To specify a click:
$(function() {
for ( i=0; i < parseInt(ids); i++){
var vst = '#'+String(img_arr[i]);
var dst = '#'+String(div_arr[i]);
$(vst).click(function (evt) {
...
});
}
})
Note that since vst is changing in the loop, your event code should also be placed in the loop.
EDIT: Assuming you want the same thing to happen for each image and each div, you could also do something like this:
$(function () {
function imgEventSpec($evt) {
// image clicked.
}
function divEventSpec($evt) {
// div clicked.
}
for (var idx = 0; idx < img_arr.length && idx < div_arr.length; idx ++) {
$("#" + img_arr[idx]).click(imgEventSpec);
$("#" + div_arr[idx]).click(divEventSpec);
}
});
I am writing a piece of code that changes some lights on a screen from red to green randomly and waits for the user to hit the key that corresponds to the light lit.
When I run this code you are able to hit the a,d,j or l key and an alert will pop up. However, as soon as I click the start button no keys are recognised. And when the loop has finished the bind still seems to become disabled. I have tried moving the bind to other places but I have had no joy. Your help is much appreciated.
$( function() {
$('#start').bind('click', function() { main(); });
$(document).bind('keypress', function(e) { keyPress(e); } );
} );
function getRand(val) {
return Math.floor(Math.random()*val)+1;
}
function main() {
preD = new Date;
preDs = preD.getTime();
randTime=Math.floor(Math.random()*1001)+1500;
playSound();
flash();
}
function flash() {
zone = getZone();
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_grn.jpg)");
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_red.jpg)");
if(cond[1] < 8) {
main();
}
} , 200);
} , randTime);
}
function getZone() {
if(condition==1) {
zone = getRand(2);
if( test[1][zone] < 8 ) {
test[1][zone] += 1;
cond[1] += 1;
return zone;
} else {
getZone();
}
}
}
function keyPress(e) {
var evtobj=window.event? event : e //distinguish between IE's explicit event object (window.event) and Firefox's implicit.
var unicode=evtobj.charCode? evtobj.charCode : evtobj.keyCode
var actualkey=String.fromCharCode(unicode)
if (actualkey=="a" || actualkey=="d" || actualkey=="j" || actualkey=="l" ) {
dd = new Date;
reat = dd.getTime();
alert(1);
//keypressed[condition][zone]['k']=actualkey;
//keypressed[condition][zone]['t']=(reat-preDs);
}
}
The reason that this could be happening is, when you generate code dynamically or alter any existing code the bind needs to be done again, because the function to bind just runs once and only for the members already created. So when you create dynamically code, you are forced to run the binding function to recognize the new elements.
this ways is not very recommended, instead of this, you could bind a container like 'div' or something and inside of this validate which element is calling you. This will work because your container is created once and the binding is properly assigned and doesn't matter if the content of your container changes, the binding always work.
Regards
Using a jquery sound plugin was the answer.
Fixed it with this : plugins.jquery.com/project/sound_plugin