Mouse click not working in button added in DOM - javascript

i am trying to add this code in my code where i want to have this button in my scene !
function performAnnotation(event: MouseEvent) {
console.log(event)
console.log('hello')
}
function loadAnnotationIntoScene() {
const menuPanel = document.getElementById('menu-panel') as HTMLDivElement
const _menuList = document.createElement('ul') as HTMLUListElement
menuPanel.appendChild(_menuList)
annotation.forEach((element, index) => {
const myList = document.createElement('li') as HTMLLIElement
const _list = _menuList.appendChild(myList)
const myButton = document.createElement('button') as HTMLButtonElement
myList.appendChild(myButton)
myButton.classList.add('annotationButton')
myButton.innerHTML = element['text']
myButton.addEventListener('click', performAnnotation, false)
})
}
i am trying to create an annotation menu above the scene in right or left hand side but i am not able to add button with event listener !!!
When i try in fiddle it works fine but in three.js, it doesn't and i believe this is because of the orbit controller that i have in my scene !!
Right now my scene is like this:
function performAnnotation(event) {
console.log("hello")
}
const annotation = [1, 2, 3, 4]
function loadAnnotationIntoScene() {
const menuPanel = document.getElementById('menu-panel')
const _menuList = document.createElement('ul')
menuPanel.appendChild(_menuList)
annotation.forEach((element, index) => {
const myList = document.createElement('li')
const _list = _menuList.appendChild(myList)
const myButton = document.createElement('button')
myButton.innerHTML = "hello"
myList.appendChild(myButton)
myButton.addEventListener('click', performAnnotation, false)
})
}
loadAnnotationIntoScene()
<div id="menu-panel"></div>
can any one suggest me what is the best thing that i can do so that i can have annotation menu in my project !!!

Related

JavaScript Class Function not accessible by Event Listener

The toggleLid function defined in my class is not working when called in an event listener. The individual 'backpack' objects are defined elsewhere. The browser is not throwing any errors in the console. Any advice is appreciated!
function Backpack (
name,
lidOpen
) {
this.name = name;
this.lidOpen = lidOpen;
this.toggleLid = (lidStatus) => {
this.lidOpen = lidStatus;
};
};
const backPackList = [bag1, bag2];
const content = backPackList.map((backpack) => {
let backpackArticle = document.createElement("article");
backpackArticle.classList.add("backpack");
backpackArticle.setAttribute("id", backpack.id)
backpackArticle.innerHTML = `
<h1>${backpack.name}<h1>
<h2>${backpack.lidOpen}<h1>
<button class='lid-toggle'>Toggle Lid</button>
`;
const button = backpackArticle.querySelector(".lid-toggle")
button.addEventListener("click", () => {
backpack.toggleLid(!backpack.lidOpen)
})
return backpackArticle;
});

Event listeners don't get re-attached to my HTML elements when using ES6 without re-feshing the page

I am printing a simple string to the screen. When clicking on one of its letters, is should be removed from wherever it is the string and added at the end. After I click on one letter and the new string is getting printed to the page, the letters don't preserve their event listeners. This is the JS code and here is all the code https://codesandbox.io/s/reverse-array-forked-fvclg?file=/src/index.js:0-1316:
const appBox = document.getElementById("app");
const convertString = (string) => {
let stringToArray = string.split("");
return stringToArray;
};
let stringToArray = convertString("Hello world!");
const printArrayToPage = (string) => {
string.forEach((element) => {
const textBox = document.createElement("div");
if (element !== " ") {
textBox.classList.add("letter");
} else {
textBox.classList.add("emptySpace");
}
const text = document.createTextNode(element);
textBox.appendChild(text);
appBox.appendChild(textBox);
});
};
window.onload = printArrayToPage(stringToArray);
const moveLetter = (event) => {
const targetLetter = event.target;
const letterToRemove = targetLetter.innerHTML;
targetLetter.classList.add("invisible");
if (stringToArray.includes(letterToRemove)) {
const index = stringToArray.indexOf(letterToRemove);
stringToArray.splice(index, 1);
}
stringToArray.push(letterToRemove);
appBox.innerHTML = "";
printArrayToPage(stringToArray);
};
const allLetters = document.querySelectorAll(".letter");
allLetters.forEach((element) => element.addEventListener("click", moveLetter));
const allSpaces = document.querySelectorAll(".emptySpace");
allSpaces.forEach((element) => element.addEventListener("click", moveLetter));
I tried moving the even assignments (this block)
const allLetters = document.querySelectorAll(".letter");
allLetters.forEach((element) => element.addEventListener("click", moveLetter));
const allSpaces = document.querySelectorAll(".emptySpace");
allSpaces.forEach((element) => element.addEventListener("click", moveLetter));
inside printArrayToPage function but because I am using ES6 syntax, I can't use a function before its definition. If I change to functions created used the function keyword, everything works as expected. How can I fix this issue using ES6 so that after I click on a letter and the divs get re-added to the page, event listeners are re-assigned?
If you want to move the letter node to the end, you can use the Node.parentNode property, and append the child node to the end. You don't need to create the nodes every time an item is clicked:
const moveLetter = (event) => {
const targetLetter = event.target;
const parent = targetLetter.parentNode;
parent.appendChild(targetLetter); // move the element to the end
};
See: https://codesandbox.io/s/reverse-array-forked-lf333?file=/src/index.js
Use event delegation. Here's a simple example snippet:
// adding an event listener to the document
document.addEventListener("click", evt => {
console.clear();
const origin = evt.target;
// ^ where did the event originated?
if (origin.closest("#bttn1")) {
console.log("you clicked button#bttn1");
} else if (origin.closest("#bttn2")) {
console.log("you clicked button#bttn2")
}
});
createElement("h3", "header", "Wait 2 seconds...");
// creating buttons after a while. The earlier created
// event listener will detect clicks for the new buttons
setTimeout( () => {
createElement("button", "bttn1", "click me");
createElement("button", "bttn2", "click me too");
}, 2000);
function createElement(nodetype, id, text) {
document.body.appendChild(
Object.assign(document.createElement(nodetype), {id, textContent: text})
);
}
body {
font: normal 12px/15px verdana, arial;
margin: 2rem;
}
button {
margin: 0 0.6rem 0 0;
}

I can't nake Reset Button

I need to make reset button which makes Resetting Scores. Can anyone help me?
I tried all my best but I don't know how to make it.
https://github.com/SandroGamrekelashvili/New-folder
const game = () => {
let pScore = 0;
let cScore = 0;
});
const startGame = () => {
const playBtn = document.querySelector(".intro button");
const introScreen = document.querySelector(".intro");
const match = document.querySelector(".match");
There were a few things you needed to get done to make the reset work.
1.) Assign reset button element to a const.
2.) Move your score elements to parent scope.
const game = () => {
let pScore = 0;
let cScore = 0;
const resetBtn = gameContainer.querySelector("button.startOver");
const playerScore = document.querySelector(".player-score p");
const computerScore = document.querySelector(".computer-score p");
// The rest of your code...
2.) Attach event listener to reset button.
const startGame = () => {
playBtn.addEventListener("click", () => {
introScreen.classList.add("fadeOut");
match.classList.add("fadeIn");
});
resetBtn.addEventListener("click", () => {
playerScore.innerText = '0';
computerScore.innerText = '0';
pScore = cScore = 0;
});
};
Here is a JSFiddle with a working example.
I think what you need to solve your problem is very well explained in this other questions here.
The idea is that instead of declaring your variable inside your main function, you would create a variable that refer to your functions related to your score outside of it that can then be called when you need it. To avoid global conflict, you would have that function return an object with functions inside for getters and setters. In your case, I would do something like this:
const scoreModule = () => {
let pScore = 0;
let cScore = 0;
return {
getPScore: () => pScore,
getCScore: () => cScore,
setPScore: value => pScore = value,
setCScore: value => cScore = value,
}
}
Because you defined the scoreModule as a global object, you can then use it wherever you want. And, because you returned only getters and setters (not the actual value, but rather a mean to get or change them) your object is protected and you avoid the bad practice of globally available variables. Then in any of your other functions, when you want to use them either to get or set them, you simply:
const game = () => {
// To get a score
const currentPScore = scoreModule().getPScore()
// To set a score
scoreModule().setPScore(newScore)
});

How do I insert multiple buttons with bound events?

I have a factory that creates buttons,
var btnFactory = (fn, text) => {
var btn = $(`<button>${text}</button>`);
btn.bind("click", fn);
return btn;
};
I want to be able insert multiple buttons, events already bound to handlers, into an element so I end up with,
<div>
<button>Button1</button>
<button>Button2</button>
</div>
I'm trying to figure out to use .html() for it, but so far it's eluded me.
You don't need jQuery (and it's more efficient)
// reusable template element for cloning
const btnTemplate = (() => {
const bt = document.createElement("button")
bt.type = "button"
// other things you want all buttons to have, classname, etc.
return bt
})()
const btnFactory = { fn, text } => {
const btn = btnTemplate.cloneNode(false)
btn.onclick = fn
btn.innerHTML = text
return btn
}
Can be used like
const items = [
{ text: "Button1", fn: e => console.log("Button1 clicked") },
{ text: "Button2", fn: e => console.log("Button2 clicked") }
]
// Higher-order helper to fold a collection and a factory into
// a documentFragment
const intoDocFrag = (factoryFn, xs) =>
xs.reduce((frag, x) => {
frag.appendChild(factoryFn(x))
return frag
}, document.createDocumentFragment())
document.body.appendChild(intoDocFrag(btnFactory, items))
I think what you're asking is how to use this function to generate the button? I put a couple different ways to do that in the snippet below:
var btnFactory = (fn, text) => {
var btn = $(`<button>${text}</button>`);
btn.bind("click", fn);
return btn;
};
// method 1
$('body').html(
btnFactory(
(function () {
console.log('test 1')
}),
'test 1'
)
)
// method 2
$('body').append(
btnFactory(
(function () {
console.log('test 2');
}),
'test 2'
)
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app"></div>
If you mean inserting a series of buttons with a for loop, then it's quite simple. You need to give the div element an ID, and create an variable like so: var divElement = document.getElementById('divElement1');. Then you create a for loop, and insert the amount of buttons like so:
var docFrag = document.createDocumentFragment()
for (var i = 1; i < (amount of buttons you want); i++)
{
var button = document.createElement("button");
button.addEventListener("click", fn);
button.value = "Button" + i;
docFrag.appendChild(button);
}
divElement.appendChild(docFrag);
Hope this helps!

GNOME Shell Extension Button

I'm trying to write an extension with just using JavaScript. I wrote it with Python through Hello World! code. But, yet in the beginning, my button for menu items is not working. Also, I couldn't add menu item with Hello World! code. I think, I miss something.
The button code is here:
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;
const TimeButton = new Lang.Class({
Name: "Salah Time",
Extends: PanelMenu.Button,
_init: function () {
let box = new St.BoxLayout({
style_class: "system-status-icon"
});
let label = new St.Label({text: "Salah Time"});
box.add_child(label);
this.actor.addActor(box);
}
});
function init() {
}
function enable() {
let but = new TimeButton();
Main.panel._leftBox.insert_child_at_index(but, 1);
}
function disable() {
Main.panel._leftBox.remove_child(but);
}
There is no many tutorial for GJS. I'm already trying to write by reading other extensions.
Thanks.
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;
const TimeButton = new Lang.Class({
Name: "TimeButton",
Extends: PanelMenu.Button,
_init: function () {
this.parent(null, "TimeButton");
// Icon
this.icon = new St.Icon({
icon_name: "appointment-symbolic",
style_class: "system-status-icon"
});
this.actor.add_actor(this.icon);
// Menu
this.menuItem = new PopupMenu.PopupMenuItem("Salah Time", {});
this.menu.addMenuItem(this.menuItem);
}
});
function init() {
}
function enable() {
let indicator = new TimeButton();
Main.panel.addToStatusArea("should-be-a-unique-string", indicator);
// hide
Main.panel.statusArea["should-be-a-unique-string"].actor.visible = false;
// change icon
Main.panel.statusArea["should-be-a-unique-string"].icon.icon_name = "appointment-soon-symbolic";
// show
Main.panel.statusArea["should-be-a-unique-string"].actor.visible = true;
}
function disable() {
// you could also track "indicator" and just call indicator.destroy()
Main.panel.statusArea["should-be-a-unique-string"].destroy();
}
Hope that helps someone (if you aren't around anymore).

Categories