window. onload=function() just works without cached DOM - javascript

The product image is displayed as inline SVG and receives a new color for specific paths, depending on the dropdown selection.
"use strict";
window.onload=function(){
var dropdownColor = document.getElementById('Color');
// When a new <option> is selected
dropdownColor.addEventListener('change', function() {
var selectPathSvg = document.getElementById('pathNumber');
//get value text
var colorValue= selectElemFerse.options[selectElemFerse.selectedIndex].text;
//Clear all Classes from SVGPath
selectPathSvg .classList = '';
// Add that class to the <p>
selectPathSvg.classList.add(colorValue);
})
}
But this Javascript code works only, if the page was read in the DOM for the first time. If you reload this page with F5, this will not lead to any errors in the console, but not to the desired result.
EDIT: Nothing here worked for me. But I noticed that if I delete the `woocommerce_recently_viewed``cookie, that the systems works fine. But how to fix such a thing?

It's generally bad practice to use onload = ... You should instead try using addEventListner("load", ...)
The reason your script does not run, is because it gets compiled after the page has been fully loaded, so you should also check if the load event has already been fired.
"use strict";
if(document.readyState === "complete") onLoad();
else addEventListener("load", onLoad);
function onLoad(){
console.log("Doing on load stuff here...");
}

Try this instead and see if it works:
window.addEventListener('DOMContentLoaded', (event) => {
var dropdownColor = document.getElementById('Color');
// When a new <option> is selected
dropdownColor.addEventListener('change', function() {
var selectPathSvg = document.getElementById('pathNumber');
//get value text
var colorValue= selectElemFerse.options[selectElemFerse.selectedIndex].text;
//Clear all Classes from SVGPath
selectPathSvg .classList = '';
// Add that class to the <p>
selectPathSvg.classList.add(colorValue);
})
});

Related

Move color of an HTML element to another page

Good evening,
i was working on a part of what i hope will be my future website and i wanted to add a "photograpy" section to it, and here comes the problem.
since the title in the main page constatly changes color, i'd like to grab its current color to transfer it to the title of the other page to play an animation later on.
the problem is that when i press the related button, i am taken to the photograpy page, but the title remains black.
i've tried seraching for help on google but i haven't been able to find much.
here is the JS
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
loaded();
});
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
loaded();
});
}
function loaded() {
document.getElementById("PHtitle").style.color === titlecolor;
}
function script() {
const titlecolor = document.getElementById("title").style.color;
};
document.getElementById('photograpy').onclick = function () {
script();
};
The snippets don't allow for localStorage, so here is just the javascript.
First, I let the variables outside of a function. The titleColor function checks to see if titleColor was saved in localStorage, if not the default color is black.
Then I set the color of the phtitle to the contents of titleColor variable.
In the script function, I set the localStorage variable to the getComputedStyle color of the title.
Then last I use an event listener on the button to run the script for saving the color.
LocalStorage is a way to store data in the user's browser until they close their browser/clear their data etc.. Which will allow it to be usable on different pages then where it was saved.
let titleColor = localStorage.getItem("titleColor") || "#000000";
let PHtitle = document.querySelector("#PHtitle");
let title = document.querySelector("#title");
let btn = document.querySelector("#photography");
if(PHtitle){
PHtitle.style.color = titleColor;
}
function script() {
localStorage.setItem("titleColor", getComputedStyle(title).color)
}
if(btn && title){
btn.addEventListener("click", function() {
script();
})
}

Appending a button on a div after div loads in the dom

I am trying to access an div (or here a tr tag) on which i want to append a button . But i am unable to access the tr tag because its loading after sometime and is not present in the DOM at that moment and getting error .
how to access a tag after loading something on the DOM
<script>
var btn = document.getElementById('btnn');
var tab = document.getElementsByClassName("scope")[0];
tab.append(btn)
</script>
I think your document.getElementById code should only be executed after everyting has been loaded. You could add an "load" Eventlistener and put your code inside it.
window.addEventListener("load", function(){
var btn = document.getElementById('btnn');
var tab = document.getElementsByClassName("scope")[0];
tab.append(btn)
});
By the way: I always use "defer" for my includes, like this:
<script src="{{ asset('/general/js/local.js') }}" defer></script>
This makes sure the "load" event will only be triggered after all includes have been loaded.
You could watch the DOM using the MutationObserver API. If the element you're observing is added, you could then apply your other code (e.g., append a button).
Basic Example:
let watchDOM = (function(){
let mo = window.MutationObserver;
return function(obj, callback){
if (!obj || !obj.nodeType === 1) {
return;
}
if (mo) {
let obs = new mo(function(mutations, observer) {
callback(mutations);
});
obs.observe(obj, { childList:true, subtree:true });
}
else if (window.addEventListener){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
watchDOM(document.body, function(e) {
// This will notify you if a new DIV is added.
if (e[0].addedNodes[0].tagName === "DIV") {
// If the DIV is added, you can then take some action here.
// For example, you could append your button here.
console.log("div added");
}
});
// This adds a new DIV after 3 seconds of running the script
setTimeout(function() {
let newDiv = document.createElement("div");
document.body.appendChild(newDiv);
}, 3000);
Is this DIV getting created in the response of an AJAX call. If that is the case then you need to call you your button appending logic once the response of AJAX call has been received.
OR use this:
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
// - Code to execute when all DOM content is loaded.
// - including fonts, images, etc.
});
</script>

Waiting for multiple iFrames to load before executing function

Forgive my naivety, this probably is quite obvious, I just can't see it now.
Please tell me what is wrong with the following code:
$('#iframe1').load(function(){
$('#iframe2').load(function(){
alert('loaded!');
});
});
The idea is to wait until both iframes have fully loaded, then alert "loaded" - of course this is a simplified example for the sake of stack.
The script sits in script tags at the end of the body of the html doc.
#Quertiy answer is perfectly fine, but not very jQuery-ish. It is hard-coded for 2 iframes only.
The beauty of jQuery is that you can make it work for the most number of people, with as little friction as possible.
I've advised a very simplistic plugin that does nearly what is present on that answer, but in a more open way. It not only works on iframes, but also on images, audio, video and whatever has a onload event!
Without further due, here's the code:
(function($){
$.fn.extend({allLoaded: function(fn){
if(!(fn instanceof Function))
{
throw new TypeError('fn must be a function');
}
var $elems = this;
var waiting = this.length;
var handler = function(){
--waiting;
if(!waiting)
{
setTimeout(fn.bind(window), 4);
}
};
return $elems.one('load.allLoaded', handler);
}});
})(window.jQuery);
It works by adding a load handler to every element in that selection. Since it is a plugin, you can use in whatever way you decide to use it.
Here's an example, that loads 30 random images:
//plugin code
(function($){
$.fn.extend({allLoaded: function(fn){
if(!(fn instanceof Function))
{
throw new TypeError('fn must be a function');
}
var $elems = this;
var waiting = this.length;
var handler = function(){
--waiting;
if(!waiting)
{
setTimeout(fn.bind(window), 4);
}
};
return $elems.one('load.allLoaded', handler);
}});
})(window.jQuery);
$(function(){
//generates the code for the 30 images
for(var i = 0, html = ''; i < 30; i++)
html += '<img data-src="http://lorempixel.com/g/400/200/?_=' + Math.random() + '">';
//stuffs the code into the body
$('#imgs').html(html);
//we select all images now
$('img')
.allLoaded(function(){
//runs when done
alert('loaded all')
})
.each(function(){
//the image URL is on a `data` attribute, to delay the loading
this.src = this.getAttribute('data-src')
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<div id="imgs"></div>
Your problem, as said before many times, is that you have a load event attached to your iframe. That event is fired everytime the content change.
After that, you set a new event on #iframe2. When it's content changes, it will fire events left and right, above and beyound what you wish!
The best aproach is to keep track of which ones you loaded or not. After all have been loaded, you simply run the function.
The problem is that you're waiting until #iframe1 loads before you attach a handler for #iframe2 loading. So if #iframe2 loads first, you'll never get your callback.
Instead, watch the load event on both of them and track which ones you've seen:
var seen1 = false,
seen2 = false;
$('#iframe1, #iframe2').load(function(){
if (this.id == "iframe1") {
seen1 = true;
} else {
seen2 = true;
}
if (seen1 && seen2) {
alert('loaded!');
}
});
Why do you expect 2nd iframe to load after the first one?
~function () {
var loaded = 0;
$('#iframe1, #iframe2').load(function (){
if (++loaded === 2) {
alert('loaded!');
}
});
}()

jQuery, update content when necessary

I'm trying to update contents of a chat located in div (div1) but only when the contents of div1 change (a message was submitted into db and picked up in div1).
I tried the solution from here but my get fails to compare the data.
This solution works perfectly but without content comparison:
window.onload = startInterval;
function startInterval()
{
setInterval("startTime();",2000);
}
function startTime()
{
jQuery('#div1').load('index.php #div1 > *');
}
This is the modification based on this, which fails:
window.onload = startInterval;
function startInterval()
{
setInterval("startTime();",2000);
}
function startTime()
{
var $main = $('#div1');
$.get('chat.php #div1', function (data)
{
if ($main.html() !== data) $main.html(data);
});
}
I tried various modifications of this code but to no avail...
I can't reload the entire page and I don't want to do this if not necessary since it makes the chat harder to read if you have to scroll trough the messages.
How can this be fixed?
UPDATE
Based on #T.J's suggestions I modified the code which now works perfectly:
window.onload = startInterval;
function startInterval()
{
setInterval(startTime,3000);
scrolDown();
}
function startTime()
{
var $main = $('#div1');
$.get('#div1', function (data)
{
elements = $(data);
thisHTML = elements.find("#div1").html();
if ($main.html() !== thisHTML) {
$main.html(thisHTML);
scrolDown();
}
});
}
The other problem was that get required library:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.pack.js"></script>
which apparently was not required by the load which I used previously.
You want to use get, but you want the fragment feature of load, so you'll have to do that work yourself. Then remember what you got last time, and only update if it's not the same:
var lastHTML;
function startTime()
{
var $main = $('#div1');
$.get('chat.php', function (data) // <== Or index.php, the question has both
{
var elements, html;
// Turn the HTML into elements
elements = $(data);
// Get the HTML of *only* the contents of #div1
html = elements.find("#div1").html();
// If that has changed, use it
if (lastHTML !== thisHTML) {
lastHTML = thisHTML;
$main.html(thisHTML);
}
});
}
Note that that's a fairly basic implementation of the fragment feature (it doesn't, for instance, strip out scripts the way load does). You may want to look at how load does its fragment stuff and replicate that (the joy of open source).

GetElementById of ASP.NET Control keeps returning 'null'

I'm desperate having spent well over an hour trying to troubleshoot this. I am trying to access a node in the DOM which is created from an ASP.NET control. I'm using exactly the same id and I can see that they match up when looking at the HTML source code after the page has rendered. Here's my [MODIFIED according to suggestions, but still not working] code:
ASP.NET Header
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onchange = alert('test!!');
)
</script>
</asp:Content>
ASP.NET Body
<asp:TextBox ID="txtBox" runat="server"></asp:TextBox>
Resulting Javascript & HTML from above
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('MainContent_txtBox');
el.onchange = alert('test!!');
)
</script>
...
<textarea name="ctl00$MainContent$txtBox" id="MainContent_txtBox"></textarea>
I can only assume that the script is loading before the control id has been resolved, yet when I look at the timeline with Chrome's "Inspect Element" feature, it appears that is not the case. When I created a regular textarea box to test and implement the identical code (different id of course), the alert box fires.
What on earth am I missing here? This is driving me crazy >.<
EDIT: Wierd code that works, but only on the initial page load; firing onload rather than onchange. Even jQuery says that .ready doesn't work properly apparently. Ugh!!
$(document).ready(function() {
document.getElementById('<%= txtBox.ClientID %>').onchange = alert('WORKING!');
})
Assuming the rendered markup does appear in that order, the problem is that the element doesn't yet exist at the time your JavaScript is attempting to locate it.
Either move that JS below the element (preferably right at the end of the body) or wrap it in something like jQuery's document ready event handler.
Update:
In response to your edits, you're almost there but (as others have mentioned) you need to assign a function to the onchange event, not the return result of alert(). Something like this:
$(document).ready(function() {
// Might as well use jQuery to attach the event since you're already using
// it for the document ready event.
$('#<%= txtBox.ClientID %>').change(function() {
alert('Working!');
});
});
By writing onchange = alert('Working');, you were asking JavaScript to assign the result of the alert() method to the onchange property. That's why it was executing it immediately on page load, but never actually in response to the onchange event (because you hadn't assigned that a function to run onchange).
Pick up jQuery.
Then you can
$(function()
{
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onclick() { alert('test!!'); }
});
Other answers have pointed out the error (attempting to access DOM nodes before they are in the document), I'll just point out alternative solutions.
Simple method
Add the script element in the HTML below the closing tag of the element you wish to access. In its easiest form, put it just before the closing body tag. This strategy can also make the page appear faster as the browser doesn't pause loading HTML for script. Overall load time is the same however, scripts still have to be loaded an executed, it's just that this order makes it seem faseter to the user.
Use window.onload or <body onload="..." ...>
This method is supported by every browser, but it fires after all content is loaded so the page may appear inactive for a short time (or perhaps a long time if loading is dealyed). It is very robust though.
Use a DOM ready function
Others have suggested jQuery, but you may not want 4,000 lines and 90kb of code just for a DOM ready function. jQuery's is quite convoluted so hard to remove from the library. David Mark's MyLibrary however is very modular and quite easy to extract just the bits you want. The code quality is also excellent, at least the equal of any other library.
Here is an example of a DOM ready function extracted from MyLibrary:
var API = API || {};
(function(global) {
var doc = (typeof global.document == 'object')? global.document : null;
var attachDocumentReadyListener, bReady, documentReady,
documentReadyListener, readyListeners = [];
var canAddDocumentReadyListener, canAddWindowLoadListener,
canAttachWindowLoadListener;
if (doc) {
canAddDocumentReadyListener = !!doc.addEventListener;
canAddWindowLoadListener = !!global.addEventListener;
canAttachWindowLoadListener = !!global.attachEvent;
bReady = false;
documentReady = function() { return bReady; };
documentReadyListener = function(e) {
if (!bReady) {
bReady = true;
var i = readyListeners.length;
var m = i - 1;
// NOTE: e may be undefined (not always called by event handler)
while (i--) { readyListeners[m - i](e); }
}
};
attachDocumentReadyListener = function(fn, docNode) {
docNode = docNode || global.document;
if (docNode == global.document) {
if (!readyListeners.length) {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded',
documentReadyListener, false);
}
if (canAddWindowLoadListener) {
global.addEventListener('load', documentReadyListener, false);
}
else if (canAttachWindowLoadListener) {
global.attachEvent('onload', documentReadyListener);
} else {
var oldOnLoad = global.onload;
global.onload = function(e) {
if (oldOnLoad) {
oldOnLoad(e);
}
documentReadyListener();
};
}
}
readyListeners[readyListeners.length] = fn;
return true;
}
// NOTE: no special handling for other documents
// It might be useful to add additional queues for frames/objects
else {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded', fn, false);
return true;
}
return false;
}
};
API.documentReady = documentReady;
API.documentReadyListener = documentReadyListener;
API.attachDocumentReadyListener = attachDocumentReadyListener;
}
}(this));
Using it for your case:
function someFn() {
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
}
API.attachDocumentReadyListener(someFn);
or an anonymous function can be supplied:
API.attachDocumentReadyListener(function(){
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
};
Very simple DOM ready functions can be done in 10 lines of code if you just want one for a specific case, but of course they are less robust and not as reusable.

Categories

Resources