This question already has answers here:
What is the difference between a function call and function reference?
(6 answers)
How to access the webpage DOM/HTML from an extension popup or background script?
(2 answers)
Closed 14 days ago.
I am developing a Chrome plugin and I am facing a challenge where a function I call uses a variable to get element by class name. The variable returns undefined as the function gets called before the particular element is loaded in the DOM.
Please see the code below -
(() => {
let wfLeftControls;
let currentProject = "";
let dynButtons;
const newProjectLoaded = async () => {
const notesBtnExists = document.getElementsByClassName("notes-button")[0];
if (!notesBtnExists) {
const notesBtnElement = document.createElement("div");
const notesBtnSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const notesBtnPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
notesBtnElement.className = "button " + "top " + "notes-button ";
/* active class highlights that the menu is active */
notesBtnSvg.setAttribute('viewBox', '0 0 45 45');
notesBtnSvg.setAttribute('fill', '#ffffff');
notesBtnSvg.classList.add('bem-Svg');
notesBtnSvg.setAttribute('style', 'display: block; position: relative;');
notesBtnPath.setAttribute('d', 'M9 39h30V20.25L27.75 9H9v30Zm0 3q-1.25 0-2.125-.875T6 39V9q0-1.25.875-2.125T9 6h20l13 13v20q0 1.25-.875 2.125T39 42Zm4.95-8.55h20.1v-3h-20.1Zm0-7.95h20.1v-3h-20.1Zm0-7.95h13.8v-3h-13.8ZM9 39V9v30Z');
notesBtnPath.setAttribute('fill', '#fffff');
notesBtnSvg.appendChild(notesBtnPath);
notesBtnElement.appendChild(notesBtnSvg);
notesBtnElement.addEventListener("click", NotesPanelEventHandler);
/* to open or close notes panel when user clicks icon */
setTimeout(() => {
wfLeftControls = document.getElementsByClassName("left-sidebar-links")[0];
wfLeftControls.appendChild(notesBtnElement);
}, 5000);
}
};
chrome.runtime.onMessage.addListener((obj, sender, response) => {
const { type, projectID } = obj;
if (type === "NEW") {
currentProject = projectID;
newProjectLoaded();
}
});
window.onload = newProjectLoaded();
})();
So here, newProjectLoaded() is the function being called.
Since the code is exectued before the element "left-sidebar-links" is loaded, the variable wfLeftControls returns undefined
So I have set a 5 second timeout to fix this problem.
Can someone please help me with how to call this function newProjectLoaded(); after all DOM elements are loaded or left-sidebar-links is loaded?
Thanks in advance 🙏
If you need to wait till DOM is ready (all elements has been added to page) use event "DOMContentLoaded".
You have been used event "load" whitch is fired after "DOMContentLoaded".
The problem is - you didn't set newProjectLoaded as event listener, you called your function and call result was setted as listener:
// change this
window.onload = newProjectLoaded(); // function was called -> return undefined -> undefined set as event handler
// to this
window.onload = newProjectLoaded; // function set as event handler
Related
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 6 days ago.
I want to export the function manualStrobeTimeout with the values especified within the manualBPM_text.addEventListener("change")'s scope. Right now, the console logs the export as undefined, meaning that the value doesn't change from when the variable was declared. How would I export the function with the values declared within that scope? Keep in mind that I cannot declare the function's values outside of the event listener, as this would interfere with the set intervals.
Here's the relevant module's code:
import { strobeActive } from "./onBtn.js"; // variable to check if ON button is active/pressed
// manual bpm variables definition and event listener
var manualBPM = 0;
var manualBPM_interval = 0;
const body = document.querySelector("body");
var ranTimes = 0;
// strobe duration variable definition and event listener
var duration = 100;
const slider = document.getElementById("MM-duration-slider");
slider.addEventListener("input", function() {
duration = slider.value;
}, false);
var manualBPM_text = document.getElementById("manual-value");
var manualStrobeTimeout;
if (strobeActive == true) {
manualBPM_text.addEventListener("change", function() {
clearInterval(manualStrobeTimeout); // so that old value doesn't interfere with new value
manualBPM = manualBPM_text.value;
manualBPM_interval = (60 / manualBPM) * 1000;
manualStrobeTimeout = function() {
// repeat once the interval expires
setInterval(function() {
// trigger strobe
body.classList.remove("bg-black");
body.classList.add("bg-white");
// kill strobe once the strobe duration expires
setTimeout(function() {
body.classList.remove("bg-white");
body.classList.add("bg-black");
}, duration);
ranTimes++;
console.log("BPM: " + manualBPM + " (source: " + BPMvalueSource + ") | Strobe duration: " + duration + "ms | " + "Times ran: " + ranTimes);
}, manualBPM_interval);
}
}, false);
}
export { manualBPM_text };
export { manualStrobeTimeout };
I want use the imported function in the following statement (on a seperate JS file):
if (BPMvalueSource == "manual") {
manualStrobeTimeout();
console.log(manualStrobeTimeout()); // returns "undefined"
} else if (BPMvalueSource == "tap") {
tapBPM_strobe();
}
I have tried using window. to set the function as global, but to no avail. I have also made sure that I am importing and exporting correctly, and also tried using a dynamic import. This also did not work. Both JS files have the attribute type="module" especified.
The clearInterval was not clearing the interval.
The interval would not even be able to run since the wrapping function was never called
You cannot export non-constat values
let lastManualBPMValue;
if (strobeActive == true) {
manualBPM_text.addEventListener("change", function() {
lastManualBPMValue = manualBPM_text.value;
}, false);
}
export { manualBPM_text };
let manualStrobeTimeout;
export function manualStrobe() {
clearInterval(manualStrobeTimeout); // so that old value doesn't interfere with new value
manualBPM_interval = (60 / lastManualBPMValue) * 1000;
manualStrobeTimeout = setInterval(function() {
...
}, manualBPM_interval);
}
The function that is assigned to the manualStrobeTimeout variable has no return statement in it, and as such will always return undefined when executed.
If you want to check that manualStrobeTimeout is assigned a value, you may want to do console.log(manualStrobeTimeout) instead, which will log the value assigned to the variable.
With console.log(manualStrobeTimeout()) you are executing the manualStrobeTimeout function, and its return value will be fed to console.log. The return value of a JavaScript function is undefined by default.
Keep in mind that manualStrobeTimeout will not be a function unless the "change" event listener has triggered.
You didn't directly ask about this, but you may also want to look at the documentation for clearInterval(). The code is attempting to call clearInterval on a function, not an interval ID.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am building an app with Javascript and OpenLayers and while it's going fairly well, I am stuck at what I feel could be an easy problem for someone experienced.
Here is part the code where the problem lives :
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender = {};
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
let baseLayerElementValueRight = this.value;
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === baseLayerElementValueRight
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element;
console.log(layerRender);
}
});
},
false
);
}console.log(layerRender)
So Basically, I need to apply a method on the "layerRender" object variable outside of the event callback and I am quite new to programming and I struggle to find a solution to access the variable value
The console.log in the callback's event output the Object I want everytime I click on a given radio type input, but the console.log outisde it outputs an empty Object and of course don't update everytime I the event is happening.
How could I do to access the layerRender value outside of the callback?
Thanks a lot
your last console.log only happens once as the code runs through... you first declare the variable. Then you add an eventListener in a for loop then finally do console.log code executes. and it executes NOT when you're clicking
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender;
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
console.log('Click happened');
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === this.value
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element; // assign element to layerRender
// console.log if element is visible only
console.log(layerRender);
}
});
},
false
);
}
console.log(layerRender); // Happens when function initialise NOT when click happens
I have the following code. I want to trigger the action in function activityDetected(eventName) only after 100 click. How to do this ?
I know I have to put let a = 1; ++a but not sure where...
https://pastebin.com/SMsJsikE
const intervalTimeout = 2000;
//here is where code should be added. let a = 1; ++a...
function activityDetected(eventName) {
console.log(`Activity detected with the event name: ${eventName}!`);
clearInterval(activityTimeout);
activityTimeout = setInterval(recordNoActivity, intervalTimeout);
}
document.addEventListener('click', _ => {
activityDetected('click');
});
You need to declare a counter outside the function and up it by 1 when the eventName is 'click'. After that check for a % 100 and put whatever action you want to call every 100 clicks in there.
Look at the code example:
// For ease, change this to a smaller value to detect more often, higher to detect less often!
const intervalTimeout = 2000;
let a = 0;
// Here's our interval, setting up the initial capture of no activity
let activityTimeout = setInterval(recordNoActivity, intervalTimeout);
// A single function to handle the events we're listening to.
// clears the interval and restarts it, also tells us which event has cleared the interval!
//here is where code should be added. let a = 1; ++a...
function activityDetected(eventName) {
if(eventName == 'click'){
a++;
if(a%100 == 0){
// Trigger whatever you want to trigger after every 100 clicks
}
}
console.log(`Activity detected with the event name: ${eventName}!`);
clearInterval(activityTimeout);
activityTimeout = setInterval(recordNoActivity, intervalTimeout);
}
// Set listening events
document.addEventListener('keydown', _ => {
activityDetected('keydown');
});
document.addEventListener('click', _ => {
activityDetected('click');
});
As correctly pointed by others on this thread the variable a should be declared and defined outside the function but the reason why this approach would work is because of Closure
So when the function is getting invoked an execution context is created which contains
scopeChain - it contains variableObject + all parent execution context's variableObject
variableObject - it contains function arguments / parameters, inner variable and function declarations
this - the this context.
Thus the variable a values would be saved before invoking the function and the variable will keep incrementing.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
here is my code, Now some people may say why not just include the one line code in that function block but i don't want to, how do i achieve that. How can i call this.click method on "click" event of the button
var i = 0;
function el() {
this.type = "button",
this.el = false,
this.click = function () {
this.setHtml(i++);
},
this.setHtml = function (t) {
this.el.innerHTML = t;
}
fragment = document.createDocumentFragment(),
element = fragment.appendChild(document.createElement(this.type));
element.setAttribute("data-el", this.type);
element.innerHTML = "Default Button";
this.el = element;
attachEvent("click", this);
}
// this should be a seperate function ....
function attachEvent(ev, me){
//me doesn't work, but i want it to call the click method
me.el.addEventListener("click", me.click, false);//....
}
div = new el();
document.getElementById('areaA').appendChild(div.el);
Change this:
me.el.addEventListener("click", me.click, false);//....
to this:
me.el.addEventListener("click", me.click.bind(me), false);//....
When you pass only me.click, you are just passing a reference to the click function and the binding to me is lost. .bind() will create a self-binding stub function that will give you the right this value when the event handler is called.
This question already has answers here:
Pure JavaScript equivalent of jQuery click()?
(4 answers)
Closed 8 years ago.
What I have with jQuery:
if ($('#vote_c').length > 0) {
$('#vote_button').show().click();
}
I am trying to re-write it so it uses raw javascript:
if (document.getElementById('vote_c').length > 0) {
// what goes here
}
// cache lookup
var vote = document.getElementById('vote_c');
// using truthy/falsy value to determine existence
// proper test would be (vote !== null)
if (vote) {
// this is probably closest to what .show() does
// .show actually seems to track what the initial
// computed display state for the element was and
// along with .hide, toggles between the initial
// state and 'none'.
vote.style.display = '';
// mimicking .click() is done any number of ways
// but the easiest is below:
vote.onclick(); // call any registered handlers for the click event;
//
// OR (second easiest way) you could define a click event:
//
var event = new MouseEvent('click', {
"view": window,
"bubbles": true,
"cancelable": true
});
// and then "dispatch" that event to the targeted
// element which should trigger the handlers
vote.dispatchEvent(event);
}
if (document.getElementById('vote_c')) {
var btn = document.getElementById('vote_button');
btn.style.display = "inline"; //show
btn.click() //click
}
document.getElementById('vote_button').onclick = function(){
document.getElementById('vote_button').style.display = 'block';
};
Oh, my bad. I did not see the if statement, but it should point you in the right direction.