Can't get event.target.id to match in Javascript - javascript

I have three buttons nested within the buttons variable a form that are all supposed to play a certain song if the buttons within the nested element are clicked. The code to check which buttons are pressed is:
//buttons variable that the three button elements are nested in
const buttons = document.getElementById('music-choice');
//the buttons themselves
const canonButton = document.getElementById('canonButton');
const moonlightButton = document.getElementById('moonlightButton');
const _40thButton = document.getElementById('40thButton');
//variables connected to the audio elements
const canonMusic = document.querySelector('audio[id="canon"]')
const moonlightMusic = document.querySelector('audio[id="moonlight"]')
const _40thMusic = document.querySelector('audio[id="40th"]')
buttons.addEventListener('click', musicPlayer(event)); //this is js.20
function musicPlayer(event) {
if (event.target.id === 'moonlightButton') { //this is js.23
moonlightMusic.play();
}
else if (event.target.id === 'canonButton') {
canonMusic.play();
}
else if (event.target.id === '40thButton') {
_40thMusic.play();
}
}
However, everytime I try to run this code I get this error message in the console:
Uncaught TypeError: Cannot read property 'target' of undefined
at musicPlayer (index.js:23)
at index.js:20
When I use the console log of those event objects, it says that the event.target.id is moonlightButton, so I would assume that having it equal to the string moonlightButton would trigger those if and else if statements but that isn't the case. I have tried this with classnames and values and have no luck with any of them so far. I'm new to Javascript so any help would be appreciated.

As vlaz has pointed out, I was trying to pass in a nonexistent parameter to my event listener.

Related

How to get boolean output from an event handler

I'm trying to check if a 'tr' element has a nextSilbing element, using a 'DOMNodeInserted' event that will detect a DOM change whenever a tr element was added into a table element after it's inserted through a form like below:
I tried to get a boolean output from the event handler but I didn't succeed, so I tried to create a function to get that output but this was impossible unless I wrapped the statement with a console.log:
function findIdx(el) {
console.log(document.querySelector('tr:first-of-type').nextSibling === null);
}
$('tbody').on('DOMNodeInserted', function(e) {
let a = $(e.target)
findIdx(a);
})
You can cast any value to boolean type with the use of !!
const anyValidValue = 1;
console.log('valiud: ', !!anyValidValue);
const notValidValue = null;
console.log('not valiud: ', !!notValidValue);
so I belive your function can look like this:
function findIdx(el) {
return !!document.querySelector('tr:first-of-type').nextSibling;
}

React Native - Manage CheckBox states

I want to make a Quiz App.
Questions are checked after user presses Submit button.
So questions are checked all at once in the end.
I need to save user choices (answers) for each question and then later check them on submit.
I was thinking about this:
let [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
let [userAnswers, setUserAnswers] = useState([] as any);
function answerClick(value: any, key: any) {
// console.log('answer clicked');
userAnswers[currentQuestionIndex][key] = value;
// TypeError: undefined is not an object (evaluating 'userAnswers[currentQuestionIndex][key] = value')
}
My checkbox for each possible answer in the question:
<BouncyCheckbox
key={index}
onPress={(value) => {
answerClick(value, index);
}}
text={answer.title}
/>
But I get
TypeError: undefined is not an object (evaluating 'userAnswers[current][key] = value')
on Answer click
What is setUserAnswers() equivalent of userAnswers[currentQuestionIndex][key] = value?
Why am I getting undefined error?
How to do this, please help my head hurts.
You are attempting to access a non existing index in the array.
userAnsqers = [];
currentQuestionIndex = 0;
// userAnswers[currentQuestionIndex] === undefined
What are you attempting to do is adding an {} to the array lazily (only when needed). This will work:
function answerClick(value: any, key: any) {
setUserAnswers(latest => {
const out = [...latest];
while (out.length <= currentQuestionIndex) out.push({});
out[currentQuestionIndex][key] = value;
return out;
})
}
There is nothing equivalent to setUserAnswers() for userAnswers[currentQuestionIndex][key] = value (see). You may find som custom hooks to manage arrays or build your own.
First off, the userAnswers should have the key and values of everything you're trying to change. The reason you're getting undefined is because you're trying to target an object in the userAnswers array which can't be found. Also, you are modifying the userAnswers state directly and that's really wrong. That's what the setUserAnswers is for. You can do this instead.
function answerClick(value: any, key: any) {
// console.log('answer clicked');
setUserAnswers([
...usersAnswers,
{[key]: [value]}
]);
}

Modify reactjs form input value outside of react

I'm using a js lib that uses react under the hood. I want to modify it to prefill an input on a form that it renders. I only have access to the top level react component from instantiation. How can I set the value such that react picks it up?
I've tried setting el.value and $el.attr('value', 'val') to no avail. I've also tried setting the state directly with el.__reactInternalInstance$abc123._currentElement.props.value but doesn't work either.
Calling:
const event = new Event("input", { bubbles: true })
el.dispatchEvent(event)
hasn't helped either.
I came up with a solution using jquery, couldn't get it to work without a library. The first line fills the field when the user clicks the input. The second fills it when they expand operation. Note that one gets called on expanding any operation. But jquery seems to work just fine with on click. Part of the problem is that the elements are created until the operation is expanded.
$('body').on('click', 'tr[data-param-name="<INPUT NAME>"] input', setInput)
$('.opblock').on('click', setInput)
I don't have the link for where I found the below call but this seems to set the value in a way that gets picked up by react.
function setInput (e) {
let xinput = $('tr[data-param-name="<INPUT NAME>"] input')
let target = xinput[0]
if (xinput.val() == '') {
let value = "INPUT VALUE"
const setter = Object.getOwnPropertyDescriptor(target, "value").set
const prototype = Object.getPrototypeOf(target)
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set
if (setter && setter !== prototypeValueSetter) {
prototypeValueSetter.call(target, value)
} else {
setter.call(target, value)
}
const event = new Event("input", {bubbles: true})
target.dispatchEvent(event);
}
}

Phaser - error: Cannot read property 'on' of null

I'm working on a simple game using Phaser.
My code:
preload() {
this.load.image('player', 'img/player.png');
}
create() {
var player = this.add.sprite(100,100,'player');
player.inputEnabled = true;
player.input.on('pointerdown', () => {
this.scene.stop('ThisScene');
this.scene.start('NextScene');
})
}
The game should switch from one scene to another when you click on the sprite 'player'. Unfortunately, this gives an error: Cannot read property 'on' of null
Any ideas?
The reason it doesn't work is that you've got a mixture of Phaser 2 and Phaser 3 code here. The inputEnabled = true comes from Phaser 2, and the use of the on event listener is from Phaser 3.
You don't state which version you're using, though, so I'll assume 3 and fix the code for that:
preload() {
this.load.image('player', 'img/player.png');
}
create() {
var player = this.add.sprite(100,100,'player');
player.setInteractive();
player.on('pointerdown', () => {
this.scene.start('NextScene');
})
}
When a Game Object is enabled for input, you listen for the events directly on the Game Object itself, not the input component.
Have you check if the pointerdown event is working? Let's try to replace the line player.inputEnabled = true; with the line player.setInteractive();. Then, do a console.log('pointerdown event working') inside the event listener:
create() {
var player = this.add.sprite(100,100,'player');
player.setInteractive();
player.input.on('pointerdown', () => {
console.log('pointerdown event working');
this.scene.stop('ThisScene');
this.scene.start('NextScene');
})
}
Let me know if that works...If not, we'll know that the event is firing & we'll take it from there.

How to add array to parameter with function?

I am very new to programming and I am wondering if anyone can help me with this.
I am trying to make a pop up page.
I set variables for each click area which I set each area with div and placed with css.
Also for each pop up image which I put div id on each image on html and set display = "none" on css.
I want to make a function that shows one image on touchend and hide other images at the same time.
Could you help me with my code?
var pop = new Array("pop1","pop2","pop3","pop4","pop5","pop6");
var clickArea = new Array("click1","click2","click3","click4","click5","click6");
function diplay(click,show,hide){
click.addEventListner("touchend",function(){
show.style.display = "block";
hide.style.display = "none";
});
};
display("click[0]","pop[0]","pop[1,2,3,4,5]");
There are a few different issues with your code.
You used strings instead of the actual code structure references while calling display. I see that you mean for these to reference the element ids, but you must first get the element with document.getElementById(...) or jQuery's $("#...").
In the pop and clickArea arrays, you used strings, which do not have the .style object. You need to reference the elements themselves.
Your code structure is not designed to handle arrays.
You need to define the addEventListener before you need the function handler to be called. You do not want this every time.
The click argument in the display function is redundant, as it is never called.
You are using jQuery. You should have stated this! (but you're forgiven) :)
You can't reach into arrays with the syntax arrayName[#,#,#].
You misspelled "display". Whoops!
The arrays are redundant, since the code needed to be restructured.
First, in order to address Point #4, we need this code to run when the DOM has finished loading:
var clickArea = new Array("click1","click2","click3","click4","click5","click6");
clickArea.each(function(id){
$("#"+id)[0].addEventListener("touchend", display);
});
Next, we need to fix the issues with your code. They're explained above.
var pop = new Array("pop1","pop2","pop3","pop4","pop5","pop6");
function display(event){
var indx = Number(event.target.id.split(/\D/i).join(""));
$("#pop"+indx)[0].style.display = "block";
pop.each(function(ide) {
if (ide.split(/\D/i).join("") != indx-1) {
$("#"+ide)[0].style.display = "none";
}
});
};
Otherwise, great job! All of us started out like this, and believe in you! Keep it up!
P.S. You can set arrays like this [ ? , ? , ? , ? ] instead of this new Array( ? , ? , ? , ? ).
Here is an example using for loops instead of methods of Arrays etc
Start off by defining everything you can
var popup_id = ["pop1", "pop2", "pop3", "pop4", "pop5", "pop6"],
popup_elm = [], // for referencing the elements later
area_id = ["click1", "click2", "click3", "click4", "click5", "click6"],
area_elm = [], // for referencing the elements later
i; // for the for -- don't forget to var everything you use
// a function to hide all popups
function hideAll() {
var i; // it's own var means it doesn't change anything outside the function
for (i = 0; i < popup_elm.length; ++i) {
popup_elm.style.display = 'none';
}
}
// a function to attach listeners
function listenTouch(area, popup) {
area.addEventListener('touchend', function () {
hideAll();
popup.style.display = 'block';
});
// we did this in it's own function to give us a "closure"
}
Finally we are ready do begin linking it all to the DOM, I'm assuming the following code is executed after the elements exist in the browser
// setup - get Elements from ids, attach listeners
for (i = 0; i < popup_id.length; ++i) {
popup_elm[i] = document.getElementById(popup_id[i]);
area_elm[i] = document.getElementById(area_id[i]);
listenTouch(area_elm[i], popup_elm[i]);
}
You cannot treat strings as html elements.
Assuming there are elements with click area ids in the page, you may do something like (once the document is ready).
var popEls = pop.map(function (id) { return document.getElementById(id) });
clickArea.forEach(function (id) {
var clickAreaEl = document.getElementById(id);
clickAreaEl.addEventListener('click', onClickAreaClick);
});
function onClickAreaClick() {
var clickAreaNum = +this.id.match(/\d+$/)[0],
popIndex = clickAreaNum - 1;
popEls.forEach(function (popEl) {
popEl.style.display = 'none';
});
popEls[popIndex].style.display = 'block';
}

Categories