Html script src files that are linked to each other - javascript

(simplification) I have two javascript files I want to include. They inter-link each other.
Problem: If I just include them the following there is an error because source1.js needs something from source2.js and vice-versa.
How can I include inter-linking source files properly in HTML, without merging them? (Imaging various already-large files)
<head>
<script src="source1.js"></script>
<script src="source2.js"></script>
source1.js
function filtersomething() {
...
othersource.somefunction();
}
source2.js
var columns = {
text: filtersomething()
}

Added more to a working snippet. I'd use that code over some of the examples here. it deals more with arguments, promises, etc. Have to run, hope this helps.
You can place an event listener within each JS file, which would not call any functions until the dom is loaded. Doing this allows both JS files to load in and see the others functions available.
// script.js
window.addEventListener('DOMContentLoaded', (event) => {
filtersomething();
});
function filtersomething() {
...
othersource.somefunction();
}
Because these are loaded after script.js, script2.js always sees what script.JS has available. So, script.JS does not see what script2.JS has until after it is loaded
// script2.js
window.addEventListener('DOMContentLoaded', (event) => {
var columns = {
text: filtersomething()
}
});
We can also watch for a pointer, as suggested. This is useful when waiting for jQuery to load as well. So within your script files, watch for a property to be set, then execute.
<head>
<script>
function deferRun(thisMethod, scriptNum) {
if (window[scriptNum])
return thisMethod();
// No property found, set timeout of 50ms and try again
setTimeout(function() { defer(thisMethod, scriptNum) }, 50);
}
</script>
<script src="source1.js"></script>
<script src="source2.js"></script>
</head>
// script2.JS
// wait until script.js is available, then return result
var columns = {
text: deferRun(filtersomething, 'script1')
}
// Set our window property saying script loaded
window.script2 = true;
//script.js
function filtersomething() {
...
deferRun(othersource.somefunction, 'script2');
}
// Set our window property saying script loaded
window.script1 = true;
// Think of script1/script2 as <script> tags.
window.script1 = {
// script.js
filtersomething: () => {
return deferRun('somefunction', 'script2', 'message to use');
}
};
// Now "load" script2.js
window.script2 = {
somefunction: (msg) => {
return `msg response is ${msg}`
},
columns: {
// wait until script.js is available, then return result
text: deferRun('filtersomething', 'script1')
},
render: async() => {
console.log(await window.script2.columns.text);
}
};
(async() => {
await window.script2.render();
})();
<head>
<script>
// this is available to all and before either script 1 or 2 loads
function deferRun(thisMethod, property, argument = null) {
if (window[property])
return window[property][thisMethod](argument);
// No property found, set timeout of 50ms and try again
return setTimeout(function() {
deferRun(thisMethod, property, argument)
}, 50);
}
</script>
</head>
You can place an event listener within each JS file, which would not call any functions until the dom is loaded. Doing this allows both JS files to load in and see the others functions available.
<pre>
// script.js
window.addEventListener('DOMContentLoaded', (event) => {
filtersomething();
});
function filtersomething() {
...
othersource.somefunction();
}
```
Because these are loaded after script.js, script2.js always sees what script.JS has available. So, script.JS does not see what script2.JS has until after it is loaded
```js
// script2.js
window.addEventListener('DOMContentLoaded', (event) => {
var columns = {
text: filtersomething()
}
});
```
We can also watch for a pointer, as suggested. This is useful when waiting for jQuery to load as well. So within your script files, watch for a property to be set, then execute.
</pre>

Related

Javascript using DOMContentLoaded as multiple html files needed

I have some javascript that runs nicely when added to the end of a HTML file. However, I need the same script on multiple html files so attempting to add it to js file. All the links are fine as I already have other functions added. The documentation recommends using DOMContentLoaded along with a readystate function. It prints the first console.log and 'print loading' from if statement, and then stops. Can someone please help?
function addbutton(){
let cartbutton = document.getElementsByName('ropebutton');
console.log(cartbutton) // prints node []
const cart = [];
for(var i = 0; i < cartbutton.length; i++) {
let button = cartbutton[i];
console.log(button);
button.addEventListener('click', (event) => {
console.clear();
console.log(event.target);
console.log(event.target.dataset.test);
cart.push(event.target.dataset.test);
console.log(cart)
});
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addbutton);
console.log("print loading");
} else {
addbutton();
console.log("print loaded");
}
Simply add the defer attribute to the style tag <script src="URL" defer></script> then you still load the script async'ed but the script will wait to be executed after all DOMContent is loaded.

Chrome Extension: Uncaught ReferenceError: function is not defined

I am writing a Chrome Extension and I have this page:
<html>
<body>
<button id="changeColor"></button>
<script src="popup.js"></script>
</body>
</html>
With this JS (popup.js):
let changeColor = document.getElementById("changeColor");
chrome.storage.sync.get("color", ({ color }) => {
changeColor.style.backgroundColor = color;
});
changeColor.addEventListener("click", async () => {
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: setPageBackgroundColor,
});
});
function setPageBackgroundColor() {
chrome.storage.sync.get("color", ({ color }) => {
document.body.style.backgroundColor = color;
});
// Here, it says: Uncaught ReferenceError: getElementByXpath is not defined
console.log(getElementByXpath("xpath").textContent);
}
function getElementByXpath(path) {
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
Why?
Problem: the code of outer functions isn't injected.
Here's what executeScript does:
it takes the function's code as plain text IIFE i.e. (function foo() { ... })(),
it transfers the text to the web page,
it selects the "isolated world" environment where all content scripts of your extension run,
it executes that text as JavaScript code.
Solution: put all necessary code and functions inside the function you inject.
In your case getElementByXpath definition should be moved inside setPageBackgroundColor.
P.S. Naturally, the injected code can also use global variables/functions of previously injected content scripts via manifest.json's content_scripts (assuming their run_at already occurred) or executeScript.

trigger function when retargeting object is created

I have implemented this plugin https://retargeting.biz/plugins/custom in my laravel app and I have some issues not with the plugin ...
The scripts that sits on the header ... when the page is loaded it created an object _ra and the functions that needs to exectute it only when
_ra.ready !== undefined
The problem is with the functions that I need to execute only when the page is loaded and send the data - because the script only run once. For the functions that need to be trriggered on a action (button, etc...) it's not a problem.
For example this script need to be loaded when the user enter on a category page.
function send_category() {
var _ra = _ra || {};
_ra.sendCategoryInfo = {
"id": 20,
"name": "Shoes",
"url": 'url_to_the_page',
"parent": false,
"breadcrumb": []
};
if (_ra.ready !== undefined) {
_ra.sendCategory(_ra.sendCategoryInfo);
}
}
What I did is:
if (document.readyState !== 'loading') {
send_category();
} else {
document.addEventListener('DOMContentLoaded', (event) => {
send_category();
})
}
but still... sometimes
_ra.ready = undefined
because the function runs and the object _ra in not yet created and the function is not executed (_ra.sendCategory)
What would you do it, in this case ?
I was thinking to use this:
window.addEventListener('load', (event) => {
send_category();
});
but what I know load event will do it when all the images and sub-frames have finished loading.
Does this event "load" ... wait until the _ra object is created ???
Using
window.addEventListener('load', (event) => {
send_category();
});
seems to work.

How to call a javascript function from .js file on page load?

I really can't figure out how to do it. I need to call somefunc() from file.js file on page load.
My file.js contains:
function somefunc() {
pc.somefunc(gotLocalDescription,
function(error) {
console.log(error)
}, {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true
}
});
}
// Socket.io
var socket = io.connect('', {
port: 1234
});
function sendCall(call) {
socket.emit('call', call);
}
socket.on('call', function(call) {
if (call.type === 'offer') {
pc.setRemoteDescription(new SessionDescription(call));
createAnswer();
} else if (call.type === 'answer') {
console.log('10--if call type is answer');
pc.setRemoteDescription(new SessionDescription(call));
} else if (call.type === 'candidate') {
var candidate = new IceCandidate({
sdpMLineIndex: call.label,
candidate: call.candidate
});
pc.addIceCandidate(candidate);
}
});
consider using
Trigger
instead
You can simple call the function which is in another file.
Have created a plunker.Also note it has a seperate file file.js. If you using name spacing please take care of that.
Click Me
WORKING COPY
You can use this:
click
But first you must include file.js in you html
<script type="text/javascript" src="file.js">
Using window.onload (pure javascript), you can call your somefunc() of file.js on page load, as following:
function somefunc() {
alert('somefunc() of file.js called!');
/*
* Your logic goes here.
*/
}
window.onload = somefunc();
DEMO
While, if you want to use jQuery, then include jquery source first and then your custom script file containing your method and DOM ready call, as following:
function somefunc() {
alert('somefunc() of file.js called!');
/*
* Your logic goes here.
*/
}
jQuery(document).ready(function(){
somefunc();
});
// OR
jQuery(function({
somefunc();
});
First make sure you have included your file.js to head of your html and the location to file is correct.

Detect if script has already loaded or not

It seems that helloworld.js gets loaded multiple times based on the number of times I click #load. I say this because when I look at Google Chromes Developer Tools Network tab, it shows helloworld.js as many times as I click #load.
$(document).ready(function() {
$("#load").click(function(){
$.getScript('helloworld.js', function() {
hello();
});
});
});
The hello() function looks like this:
function hello(){
alert("hello");
}
Is it possible to detect if helloworld.js has already loaded?
So if it hasn't loaded, load it, and if it has loaded, don't load it.
This is what Developer Tools currently shows me if I click the #load button 4 times:
Set a flag when file loaded successfully. If flag is set then skip the file loading again.
Try this code,
var isLoaded = 0; //Set the flag OFF
$(document).ready(function() {
$("#load").click(function(){
if(isLoaded){ //If flag is ON then return false
alert("File already loaded");
return false;
}
$.getScript('helloworld.js', function() {
isLoaded = 1; //Turn ON the flag
hello();
});
});
});
So why not only fire the event once like this:
$("#load").one("click", function() {
$load = $(this);
$.getScript('helloworld.js', function() {
hello();
// bind hello to the click event of load for subsequent calls
$load.on('click', hello);
});
});
That would prevent subsequent loads and avoids the use of a global
Another option is letting .getScript() run but let it take the script from browser's cache so you won't have it reloaded each and every time.
To achieve this, add such code:
$.ajaxSetup({
cache: true
});
This is taken from the documentation page.
You could create a helper function:
var getScript = (function() {
var loadedFiles = {};
return function(filename, callback) {
if(loadedFiles[filename]) {
callback();
} else {
$.getScript(filename, function() {
loadedFiles[filename] = true;
callback();
});
}
};
})();

Categories