Undefined error for audio in array - javascript

I have an array of image .png files and a matching array of .mp3s. Clicking on the image should play the audio by passing the index from one array to the other, however I am getting the "undefined" error for the last line.
$(document).ready(function () {
var starting_pics = ["CN.gif", "EN.gif", "GN.gif"];
var starting_sounds = ["CN.mp3", "EN.mp3", "GN.mp3"];
var i = 0;
for (i = 0; i < starting_pics.length; i++) {
$("<img/>").attr("src", "images/" + starting_pics[i]).load(function () {
$(this).appendTo("#main");
$(this).addClass("pics");
});
}
for (i = 0; i < starting_sounds.length; i++) {
$("<audio/>").attr("src", "audio/" + starting_sounds[i]).load(function () {
$(this).appendTo("#main");
$(this).addClass("sound");
});
}
$("#main").on("click", ".pics", function () {
var i = $(this).index();
alert(i);
$(".sound").get(i).play();
});
});

The elements are not properly appended by using .load(), do the following modifications.
for (i = 0; i < starting_pics.length; i++) {
$("<img/>").attr("src", "" + starting_pics[i])
.appendTo("#main")
.addClass("pics");
}
for (i = 0; i < starting_sounds.length; i++) {
$("<audio/>").attr("src", "" + starting_sounds[i])
.appendTo("#main")
.addClass("sound");
}
UPDATE:
That version of .load() is deprecated since jQuery 1.8 - use $("selector").on("load, func.... And make sure you bind the load event before you set the src attribute - some browsers will fire the load event immediately when the `src is set, if it's been cached.
In addition, <audio> elements don't seem to have a load event. That's why the elements weren't being found - the load event never executed, so they weren't appended. The events you want to look into are canplay or canplaythrough, or something from this list: https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Events/Media_events

Related

index number for the line time using JavaScript

I am using the below code in the google tag manager custom JavaScript variable, but it returns same index value for every line item, what can be the issue?
Web page link: https://www.amity.edu/programe-list.aspx?fd=all
function() {
var elements = document.querySelectorAll('.staff-container');
for (var i = 0; i < elements.length; i++){
(function(index){
elements[i].children[0].children[0].addEventListener("click", myScript);
function myScript(){
return("Clicked : ",index);
}
})(i);
}
}
There is an error in the 5th line.
It should be elements[index].children... in that case.
The updated code:
function() {
var elements = document.querySelectorAll('.staff-container');
for (var i = 0; i < elements.length; i++){
(function(index){
elements[index].children[0].children[0].addEventListener("click", myScript);
function myScript(){
return("Clicked : ",index);
}
})(i);
}
}
Here is an alternative way from Simo's blog
Blog link
Although the post is say about visibility element. I test it with click on my website.
This might work
function() {
var list = document.querySelectorAll('.staff-container a'),
el = {{Click Element}};
return [].indexOf.call(list, el) + 1;
}
If it is not working, you might need to provide the screenshot about the click element from your GTM preview.

Code Working in Console BUT NOT From Script

I have a script that I'm running to detect a line break in a flex-wrapped UL.
I have this javascript function at the top of my scripts.js file outside of the $(document).ready call.
var detectWrap = function(className) {
var wrappedItems = [];
var prevItem = {};
var currItem = {};
var items = document.getElementsByClassName(className);
for (var i = 0; i < items.length; i++) {
currItem = items[i].getBoundingClientRect();
if (prevItem && prevItem.top < currItem.top) {
wrappedItems.push(items[i]);
}
prevItem = currItem;
};
return wrappedItems;
}
Inside of a $(document).ready call, I have this:
$( ".menu-item-has-children" ).click(function() {
var wrappedItems = detectWrap('menu-item-object-practice-area');
for (var k = 0; k < wrappedItems.length; k++) {
wrappedItems[k].className = "wrapped";
}
});
If I load the page and click the "Practice Areas", I get nothing. If I open up the console and drop in the following it works fine:
var wrappedItems = detectWrap('menu-item-object-practice-area');
for (var k = 0; k < wrappedItems.length; k++) {
wrappedItems[k].className = "wrapped";
}
I'm assuming this has something to do with the timing and/or what is loaded up but I'm not adding content into the DOM...I'm just adding a class.
For reference, here is the site: https://myersbrierkelly.djykrmv8-liquidwebsites.com/
When you click the drop-down menu, two separate event handlers respond:
Yours, to measure for wrapped items
The library you're using, to toggle the display of the submenu
However, as there is nothing to manage the order of these, what ends up happening is that your wrap-detector runs before the submenu is shown, and if the submenu isn't shown yet then you can't measure getBoundingClientRect() since it doesn't exist. A simple console.log(currItem) would have revealed this.
If you can't guarantee the order of events (which may well be the case when using a library), then you should delay your code by a frame.
$(".menu-item-has-children").click(function() {
requestAnimationFrame(function() {
var wrappedItems...
});
});

Can you use "this" attribute on onclick of an HTML tag?

Can you use the this tag for the onclick on an HTML tag?
Here's my JS code...
function changeImage() {
this/*<-- right there <--*/.src=a;
}
document.getElementsByTagName('img').onclick = function(){
changeImage();
} ;
Am I doing something wrong?
Use it this way...
function changeImage(curr) {
console.log(curr.src);
}
document.getElementsByTagName('img').onclick = function(){
changeImage(this);
} ;
You could use the .call() method to invoke the function with the context of this.
In this case, you would use:
changeImage.call(this)
Example Here
function changeImage() {
this.src = 'http://placehold.it/200/f00';
}
document.getElementsByTagName('img')[0].onclick = function(){
changeImage.call(this);
};
As a side note, getElementsByTagName returns a live HTMLCollection of elements. You need to apply the onclick handler to an element within that collection.
If you want to apply the event listener to the collection of elements, you iterate through them and add event listeners like this:
Updated Example
function changeImage() {
this.src = 'http://placehold.it/200/f00';
}
Array.prototype.forEach.call(document.getElementsByTagName('img'), function(el, i) {
el.addEventListener('click', changeImage);
});
Or you could simplify it:
Example Here
Array.prototype.forEach.call(document.getElementsByTagName('img'), function(el, i) {
el.addEventListener('click', function () {
this.src = 'http://placehold.it/200/f00';
});
});
You are doing two things wrong.
You are assigning the event handler to a NodeList instead of to an element (or set of elements)
You are calling changeImage without any context (so this will be undefined or window depending on if you are in strict mode or now).
A fixed version would look like this:
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].onclick = function () {
changeImage.call(this);
};
}
But a tidier version would skip the anonymous function that does nothing except call another function:
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].onclick = changeImage;
}
And modern code would use addEventListener.
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
images[i].addEventListener('click', changeImage);
}
However, images are not interactive controls. You can't (by default) focus them, so this approach would make them inaccessible to people who didn't use a pointing device. Better to use controls that are designed for interaction in the first place.
Generally, this should be a plain button. You can use CSS to remove the default padding / border / background.
If you can't put a button in your plain HTML, you can add it with JS.
var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
var image = images[i];
var button = document.createElement('button');
button.type = "button";
image.parentNode.replaceChild(button, image);
button.appendChild(image);
button.addEventListener('click', changeImage);
}
function changeImage(event) {
this.firstChild.src = a;
}

Is it possible to modify the result of a GET request with Javascript?

I'm on a website that is not mine, and an HTTP GET request is called onmouseover on a link. The result is a <table> which is removed onmouseout.
Is it possible for me to edit the contents of the <table> before it is called?
I have tried adding a second EventListener to the link but it only gets called before the <table> is created:
var matchupTable = document.getElementById('chessvs'),
matchupProfileLink = matchupTable.getElementsByTagName('a');
function getHoverProfile() {
var i, currentLink;
for (i = 0; i < matchupProfileLink.length; i += 1) {
currentLink = matchupProfileLink[i];
if (currentLink.innerHTML !== gk_uid && currentLink.title !== 'premium subscriber') {
currentLink.addEventListener('mouseover',
function hideHoverRank() {
var hoverProfile = document.getElementsByTagName('table'),
currentTable, i;
for (i = 0; i < hoverProfile.length; i += 1) {
currentTable = hoverProfile[i];
console.log(currentTable);
}
}, false);
}
}
}
getHoverProfile();
The only table in your example is in document. You can do whatever you want with it. You can also try to unbind the original get-success handler on all anchors in chessvs.

Why is my use of the <img> 'onload' event handler working sporadically?

The code below, works ... sometimes, but I don't know why it doesn't work all the time.
I'm trying to determine how many people press the "Buy Now" PayPal button that's on different webpages.
Currently, each page on the site fetches a 43 byte 1x1 gif from unique locations (thanks to mod_rewrite) that is easily grep'able in the Apache access log. My thinking was that if I could change the URL for that image with javascript, I could track the click in the access log while still having the browser's forward and back buttons work.
The code below (Override_Form_OnClick()) looks for a form on the page (there's only one) and attaches a handler (my_shopping()) to the form's onclick handler.
The my_shopping() handler then updates the image resource named my_stats (again, there's only one), attaches the form element's submit function to the image's onload handler, then returns false so that the form doesn't get submitted until the new image loads.
That's the intention, but it doesn't always log the new image in the access log. Granted, I've only been testing it in Chrome using the dev tools, so maybe it's an issue with other browsers?
<script>
function my_shopping(onload_handler, shopping_tag) {
'use strict';
var my_img_elements = document.getElementsByName('my_stats'),
my_img_url,
i,
len;
len = my_img_elements.length;
if (len > 1) {
alert("Multiple my_stats elemetns on page: only expected 1.");
}
for (i = 0; i < len; i += 1) {
my_img_url = my_img_elements[i].src;
my_img_url = my_img_url.replace(".gif", "." + shopping_tag + ".gif");
my_img_elements[i].onload = onload_handler;
my_img_elements[i].src = my_img_url;
}
return false;
}
function Override_Form_OnClick() {
'use strict';
var elements = document.getElementsByTagName('form'),
element,
i,
len;
len = elements.length;
if (len > 1) {
alert("Multiple 'form' elements on page: only expected 1.");
}
for (i = 0; i < len; i += 1) {
element = elements[i];
element.onclick = function () { my_shopping(element.submit, "shopping.PayPal") };
}
return true;
}
Override_Form_OnClick();
</script>
The policy of the website has a strong preference for using only javascript.
Maybe this will work. Let me know.
for(var i=0,l=my_img_elements.length; i<l; i++){
var mi = my_img_elements[i], ni = new Image;
ni.src = mi.src = mi.src.replace(".gif", "." + shopping_tag + ".gif");
ni.onload = onload_handler;
}

Categories