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...
});
});
Related
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.
I'm trying to change styles of many text fields on a layout of an application in RSA Archer GRC using custom object. I wrote a script and it runs only once, when the application is opened. The problem is that the layout contains multiple tabs. When tab is changed the script isn't working anymore.
So how to execute the script on every tab changing?
var tableId = 'master_DefaultContent_rts_ts3295_s4655_f18821srvgrid_ctl00';
//table with target elements
$(document).ready(function () { //run script when page is loaded
main();
});
function main() {
var table = document.getElementById(tableId).getElementsByTagName("tbody")[0];
var rows = table.getElementsByTagName("tr");
for (var i = 0; i < (rows.length - 1); i++) {
var field = rows[i].getElementsByTagName("td")[1];
var spanElements = field.getElementsByTagName("span"); //target elements
for (var k = 0; k < spanElements.length; k++) { //apply style for each of them
var elem = spanElements[k];
elem.style.fontFamily = "Times New Roman";
elem.style.fontSize = "14pt";
elem.style.color = "black";
}
}
}
Try using this in your custom object instead of $(document).ready({});, it should fire each time a tab is loaded.
function pageLoad(){
//code
}
<tabelement onclick="main()">Tab</tabelement>
Use the onclick event on the tab to execute the main function.
This is supposed to be a very simple dropdown FAQ system, I know how to do this in jQuery but I want to learn plain JS.
I just want the individual clicked triggers to toggle the is-visible class to the content divs next to the clicked trigger. Like $(this).next addClass — just in JS.
I've really tried to search for this issue but 90% that shows up is how to do it in jQuery :-p
https://jsfiddle.net/48ea3ruz/
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
// access to individual triggers:
var trigger = allTriggers[i];
}
var allContent = document.querySelectorAll('.faq-content');
for (var i = 0; i < allContent.length; i++) {
// access to individual content divs:
var content = allContent[i];
}
// I don't know how to target the faq-content div next to the clicked faq-trigger
this.addEventListener('click', function() {
content.classList.toggle('is-visible');
});
Would really appreciate some advice! :-)
Use nextSibling, when you are iterating .faq-trigger
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
allTriggers[i].addEventListener('click', function() {
this.nextSibling.classList.toggle('is-visible');
});
}
nextSibling will also consider text-nodes, try nextElementSibling also
var allTriggers = document.querySelectorAll('.faq-trigger');
for (var i = 0; i < allTriggers.length; i++) {
allTriggers[i].addEventListener('click', function() {
this.nextElementSibling.classList.toggle('is-visible');
});
}
I am trying to place background images for divs with JS and change those images on mouse over and on click. I am trying to do it like this:
window.onload; {
var replies = document.getElementsByClassName("reply-wrapper");
var retweets = document.getElementsByClassName("retweet-wrapper");
var favs = document.getElementsByClassName("fav-wrapper");
for (var i = 0; i < replies.length; i++) {
replies[i].style.backgroundImage = "url(images/reply.png);";
}
for (var i = 0; i < retweets.length; i++) {
retweets[i].style.backgroundImage = "url(images/retweet.png);";
}
for (var i = 0; i < favs.length; i++) {
favs[i].style.backgroundImage = "url(images/favorite.png);";
}
}
But for some reason it won't work. Aprropriate divs have right classes and adding them to collection works fine, but placing images itself doesn't work. What am I doing wrong?
P.S. Wanna write it in pure JS, no jQuery.
P.P.S For some reason placing image with innerHTML works fine. Why?
It looks like you've made a slight mistake when assigning your code to the window.onload event.
Your code needs to be in a function assigned to the onload event.
window.onload = function () { /* Your Code */ };
instead of:
window.onload; { /* Your Code /* }
There are two issues:
Like Jamie Dixon mentioned it needs to be window.onload = function(){}
favs[i].style.backgroundImage = "url(images/favorite.png);"; should be favs[i].style.backgroundImage = "url(images/favorite.png)"; The extra ; will cause your link not to work. So remove the extra semi-colon from the rest of your links.
Update with explanation:
#room1 {
background-image: url('image/example.png');
}
In the example above you'll notice the semi-colon. Like in any programming language this is to say that this is the end of the command. Sometimes semi-colon's are optional ( like in certain cases found in js ).
JS isn't CSS. Even if you apply a style to your html element, you are using JS and not CSS. This is why you don't need the ; inside the quotes.
The event handler window.onload needs to be assigned a function to invoke. So, you just need to add the keyword 'function' before the block of code and then assign that to window.onload. Additionally, if you want to play nice with other code on the page you could grab a reference to any existing onload handler and then invoke in your onload function.
var oldOnLoad = window.onload;
window.onload = function() {
if (typeof oldOnLoad === 'function') {
oldOnLoad();
}
var replies = document.getElementsByClassName("reply-wrapper");
var retweets = document.getElementsByClassName("retweet-wrapper");
var favs = document.getElementsByClassName("fav-wrapper");
for (var i = 0; i < replies.length; i++) {
replies[i].style.backgroundImage = "url(images/reply.png)";
}
for (var i = 0; i < retweets.length; i++) {
retweets[i].style.backgroundImage = "url(images/retweet.png)";
}
for (var i = 0; i < favs.length; i++) {
favs[i].style.backgroundImage = "url(images/favorite.png)";
}
};
Note: it might be worth mentioning that loading the background images in the onload event handler could cause your page to appear to load slow because it will wait for all other content on the page to finish loading. You might want to do something like instead:
<div id="reply-wrapper" style="display: block; width: 250px; height: 250px;"></div>
<script>
(function() {
document.getElementById('reply-wrapper').style.backgroundImage = "url(//dummyimage.com/250x250/000/fff)";
})();
</script>
I don't see a function name for the code.
Is it incomplete?
this might be the error.
window.onLoad;
Try this:
function fn_load(){
// Your statements
}
and in the body do this:
i should be:
window.onload = function() {
var replies = document.getElementsByClassName("reply-wrapper");
var retweets = document.getElementsByClassName("retweet-wrapper");
var favs = document.getElementsByClassName("fav-wrapper");
for (var i = 0; i < replies.length; i++) {
replies[i].style.backgroundImage = "url(images/reply.png);";
}
for (var i = 0; i < retweets.length; i++) {
retweets[i].style.backgroundImage = "url(images/retweet.png);";
}
for (var i = 0; i < favs.length; i++) {
favs[i].style.backgroundImage = "url(images/favorite.png);";
}
}
you DOM is calling even before window got load.
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