I've no idea if this is the right way to do what I'm trying to do (I have 0 experience with jQuery/Javascript):
window.onload = function () {
var Btn = document.getElementById('fmm-payment-btn');
Btn.onclick = function () {
gtag_report_conversion();
}
}
The gtag_report_conversion() looks like this:
function gtag_report_conversion(url) {
var callback = function () {
if (typeof(url) != 'undefined') {
window.location = url;
}
};
gtag('event', 'conversion', {
'send_to': 'AW-URLHERE',
'transaction_id': '',
'event_callback': callback
});
return false;
}
Basically, I'd like to make sure that the function gtag_report_conversion() is executed when users click on fmm-payment-btn (to track conversions in Google Ads).
I tried this in a slightly different way using document.getElementById("fmm-payment-btn").onclick = function() but I kept getting an error, Uncaught TypeError: Cannot set property 'onclick' of null. I understand the method above should work better, but having no experience I cannot tell.
Would appreciate any feedback. :)
window.onload doesn't mean that the DOM is loaded.
If you want to be sure that the button is rendered you should use
window.addEventListener('DOMContentLoaded', (event) => {
console.log('DOM fully loaded and parsed');
document.getElementById("fmm-payment-btn").onclick = function(){}
// Or
document.getElementById("fmm-payment-btn").addEventlistener('click', function(){})
// Or even cleaner
document.getElementById("fmm-payment-btn").addEventlistener('click', gtag_report_conversion)
});
Related
I have an external JS file that adds a window.onload function to the page.
The basic premise is that it loads up a popup window on your website whenever the user clicks on certain link class. It's written in PHP / JS so assume that the function works by itself.
Inside this JS file has the following code.
window.onload = function() {
var anchors = document.getElementsByClassName("vyper-triggers");
for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
anchor.onclick = function() {
if (isMobile.any()) {
window.open("$url");
} else {
document.getElementById("clickonthis").click();
}
}
}
}
Now my problem is when my user wants to add 2 different popup windows, the window.onload function doesn't stack. Also because this is an embedded javascript that my user adds himself, there is no way for me to put both functions inside one big window.onload function.
My user might put one JS file in one area of their site, and another JS file in another area, if that makes sense.
So how do I make it so that the window.onload function will stack no matter the placing of these external JS files on the page and considering that each function must be kept separate?
Rather than setting window.onload, you should use addEventListener. Listeners added this way will stack automatically.
window.addEventListener('load', function() {
console.log('First listener');
});
window.addEventListener('load', function() {
console.log('Second listener');
});
window.addEventListener('load', function() {
console.log('Third listener');
});
If you have to support versions of IE before IE9, there's a polyfill which will make this work correctly.
Probably you have multiple files and u want to check something onload.
Let's implement a basic function to add other functions and run all of them when the event onload is triggered.
So, first we check if windows.onload has a function object if not add our function. If is contains a function object merge it with our function like this:
function addLoadEvent(callback) {
const previous = window.onload
if (typeof previous === 'function') {
window.onload = (e) => {
if (previous) previous(e)
callback(e)
}
}
...
}
This is an example how to use it:
function addLoadEvent(callback) {
const previous = window.onload
if (typeof previous === 'function') {
window.onload = (e) => {
if (previous) previous(e)
callback(e)
}
} else {
window.onload = callback
}
}
function func1() {
console.log('This is the first.')
}
function func2() {
console.log('This is the second.')
}
addLoadEvent(func1);
addLoadEvent(func2);
addLoadEvent(() => {
console.log('This is the third.')
document.body.style.backgroundColor = '#EFDF95'
})
Hi I have written some javascript code to generate an iFrame and insert content inside. But I don't want to use setTimeout and I want to refactor the code. I tried to use document.ready() and window.onLoad() and they don't work.
This is my code:
onShow: function() {
//TODO: why 200 ms wait? why not wait for specific event
setTimeout(this.injectHtml.bind(this), 200);
},
injectHtml: function() {
var iframe = this.el;
if (iframe.contentWindow === null) { //Check for contentWindow for null.
$(iframe).html(this.params.html);
} else { //If contentWindow is present then open the document for writing.
iframe = iframe.contentWindow;
iframe.document.open('text/html');
iframe.document.write(this.params.html);
iframe.document.close();
$(this.el).on('load', function() {
var iframe = $(this).contents();
iframe.find("#langSelect").off("change");
iframe.find("#langSelect").on("change", function() { //If another language is selected from Dropdown.
abc.languages.setSelected($(this).val());
abc.elements.setLanguage();
Vent.trigger(Vent.Event.LANGUAGE_SELECTED, $(this).val());
});
});
}
}
I'm really confused here. Can anyone shed light?
I have tried this as well:
Case#1:
var _this=this;
$(document).ready(function(){
_this.injectHtml.bind(_this); //Does not work. Everything loads, I get empty page
});
Case#2:
window.onLoad = function(){
this.injectHtml.bind(this);
};
can anyone help?
I have got a problem with my jQuery code which supposed to detect connectivity to the internet.
function checkConnection() {
var connected = true;
var img = document.createElement('img');
img.src = "https://p5-zbjpil5uzqzqg-b5icu4xm7kglqch5-458861-i2-v6exp3-ds.metric.gstatic.com/v6exp3/6.gif";
img.onerror = function () {
connected = false;
};
return connected;
}
setInterval(function () {
var isConnected = checkConnection(); // checkConnection() comes from above code
if (isConnected) {
alert('internet');
} else {
alert('no internet');
}
}, 3000);
It doesn't matter wheater I am online or offline there is the same alert window INTERNET comes up. Can you please help to fix the code? The fiddle is available below, feel free to amend it.
http://jsfiddle.net/yV28D/2/
Many thanks.
When dealing with events, you typically want to use callbacks.
http://jsfiddle.net/yV28D/3/
function checkConnection(callback) {
var img = document.createElement('img');
img.onerror = function () {
callback(false);
};
img.onload = function() {
callback(true);
};
img.src = "https://p5-zbjpil5uzqzqg-b5icu4xm7kglqch5-458861-i2-v6exp3-ds.metric.gstatic.com/v6exp3/6.gif";
}
setInterval(function () {
checkConnection(function(isConnected){
if (isConnected) {
console.log('internet');
} else {
console.log('no internet');
}
}); // checkConnection() comes from above code
}, 3000);
Otherwise, you will always get true because the return is happening before the error callback has a chance to be executed.
Also, when dealing with onload and onerror events, you always want to bind the events before you set the src, otherwise it's possible for the event to happen before you bind to it.
The problem is that the new content will not print (a few more elements).
When the user clicks my print link then I add more html to the document before window.print() is called.
I use ajax to fetch more chapters for a book before printing.
Code:
Print initialized:
var afterPrint = function () {
var timer = setInterval(function () {
afterContentPrint(); // Cleanup html (restore to initial state)
clearInterval(timer);
}, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
Event print click:
$("#print-test").click(function (e) {
e.preventDefault();
beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});
In function beforeContentPrint():
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
The new content is visibly added to the HTML document, so it should work. But only the initial content (before ajax call) is picked up for print.
This solution is for IE and Firefox (onbeforeprint and onafterprint).
Using window.matchMedia('print') seems to work fine in Chrome with this logic.
I don't know why this is happening but there is a working around in mozilla docs; printing a hidden iframe, then you open more chapters of the book with no need to shows up.
Here the link https://developer.mozilla.org/en-US/docs/Printing
Here the code:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
document.body.removeChild(this.__container__);
}
function setPrint () {
this.contentWindow.__container__ = this;
this.contentWindow.onbeforeunload = closePrint;
this.contentWindow.onafterprint = closePrint;
this.contentWindow.print();
}
function printPage (sURL) {
var oHiddFrame = document.createElement("iframe");
oHiddFrame.onload = setPrint;
oHiddFrame.style.visibility = "hidden";
oHiddFrame.style.position = "fixed";
oHiddFrame.style.right = "0";
oHiddFrame.style.bottom = "0";
oHiddFrame.src = sURL;
document.body.appendChild(oHiddFrame);
}
</script>
</head>
<body>
<p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>
1st Attempt : try putting asyn:false in the ajax request of beforeContentPrint, so that the elements will be added first then the print will be called.
var jqxhr = $.ajax({
type: "GET",
url: bookURL,
async:false,
success: function(data) {
.....
.....
$(article).each(function () {
parent.append(article);
});
},
complete: function() {
var timer = setInterval(function () {
window.print();
}, 900);
}
}
2ndAttempt: Take a look Here how to force execution of one function after another.
Hope this helps.
As the elements added aren't shown it can be a little hard to pinpoint the exact problem, but adding elements via appending/inserting into document doesn't always work that well for all browsers and in worst case you will need to add those elements manually by code (document.createElement(), appendChild() etc.).
In an attempt to create a work-around you can try to use MutationObservers to track changes for your article element which can hopefully help you trigger print when DOM is updated properly. The support is fairly good in new browsers (you may have to use prefix in some, f.ex. WebKitMutationObserver) and for older browsers you can provide a fallback - which of course then only get you so far.
This will monitor a target element for changes and fire a callback.
Generic example based on this article:
var article = document.querySelector('#articleID'),
doPrint = false, // must be available in global/parent scope
o,
useFallback = (typeof MutationObserver !== 'undefined');
if (!useFallback) {
o = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// you can do additional filtering here
// using the mutation object (.name, .type, ...)
if (doPrint) {
doPrint = false;
window.print();
}
});
});
var cfg = { attributes: true, childList: true, characterData: true };
o.observe(article, cfg);
}
Now that the observer is running you can do this modification in your success callback:
var timer; // keep track of setTimeout so we can cancel it
success: function(data) {
...
...
$(article).each(function () {
parent.append(article);
});
// after last element is added, add a "dummy" element
doPrint = true;
if (useFallback) {
// fallback to setTimeout or other solution
}
else {
parent.append('<br />');
}
}
I made an online demo here which sets up the observer and adds some elements. Open console to see actions. The demo is probably too limited data-wise to simulate your situation but can be useful to see the process.
The mechanism used here for triggering print dialog itself can be discussed if is the best - I just provide one for sake of example.
But you can see the observer is triggered when something is added to article. This way you know the DOM has been updated and it should be available for printing. Only the last element added need to trigger the print, hence the doPrint flag.
If you still have no success you will need to consider adding the elements manually the code way or perhaps predefine some elements that you inject when needed (as said, without knowing the full scenario here it has to be with the guess).
It looks like the setInterval, clearInterval is what is messing you up. Change to a setTimeout and get rid of the clearInterval in your afterprint function. I made a fiddle that works in FF and IE9. Fiddle
complete: function() {
var timer = setTimeout(function () {
window.print();
}, 900);
}
I'm using this code, which has stemmed from here and here.
$('#my_button').on('click', function (e) {
var iframe = document.createElement('iframe');
iframe.id = "my_iframe";
iframe.onload = function() {
var doc = iframe.contentDocument || iframe.contentWindow.document;
doc.getElementsByTagName('body')[0].innerHTML = "<p>test123</p>";
iframe.contentWindow.focus();
iframe.contentWindow.print();
$("#my_iframe", top.document).remove();
};
document.getElementsByTagName('body')[0].appendChild(iframe);
});
Without the remove line, it prints fine. However, the remove line removes the iframe before it has a chance to execute the print(). How can I set up some kind of callback so that it prints and only then removes the iframe?
Thanks.
I found this solution when I was searching for print event detection:
http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
Here I add the JS code as requested by Stano, but it is important to also read the whole linked post as there are limitations to this approach. In general the post is about the onafterprint event that only works in IE and a solution to make that event work in other browsers.
(function() {
var beforePrint = function() {
console.log('Functionality to run before printing.');
};
var afterPrint = function() {
console.log('Functionality to run after printing');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
create a function like this:
function printIframe(iframe,callback) {
iframe.contentWindow.print();
if (callback && typeof(callback) === "function") {
// execute the callback, passing parameters as necessary
callback();
}
}
and call it instead of the other two functions like this.
printIframe(iframe,function(){ $("#my_iframe", top.document).remove();})
if you like you can also put in a delay using the setTimeout.
setTimeout(function() {alert('hello');},1250);