Calling a method on every instance of a class in Javascript? - javascript

I am trying to call a class' method on every instance of that class.
Currently, I have all of my classes stored in an array, called checkers[]
I loop through every instance of the class Checker() using this for loop:
this.drawCheckers = function() {
for(var checker in this.checkers) {
checker.draw();
}
}
When I run the code, I get the error:
localcheckers.js:57 Uncaught TypeError: checker.draw is not a function
How would I fix this?

In your for...in loop, the value stored in checker is not the property in this.checkers, but the property name.
What you need to do is access the property then call draw on it.
this.drawCheckers = function()
{
for(var checker in this.checkers) {
this.checkers[checker].draw();
}
}
See a working example here:
https://jsbin.com/fezixaboso/edit?js,console

call draw() only if checker is an instance of Checker
this.drawCheckers = function() {
for(var i = 0; i < this.checkers.length; i++) {
if(this.checkers[i] instanceof Checker)
this.checkers[i].draw();
}
}

Related

Referring to the calling object in JavaScript using addEventListener

I'm new to JavaScript/HTML/CSS and I can't spot the mistake I'm doing in this JavaScript function. Our teacher told us to use the addEventListener method cause it has some notable advantages.
This is my entire script with the problematic function
var espandi = function (e) {
var toHide = document.getElementsByClassName("optional");
for (var index = 0; index < toHide.length; index++)
toHide[index].style.display = "none";
var toShow = e.target.getElementsByClassName("optional");
for (index = 0; index < toShow.length; index++)
toShow[index].style.display = "block";
}
var expansibleObjects = document.getElementsByClassName("singleresult");
for (var index = 0; index < expansibleObjects.length; index++)
expansibleObjects[index].AddEventListener("click",espandi);
The fact is the line e.target.getElementsByClassName gets me an error of this type
Uncaught TypeError: Cannot read properties of undefined (reading 'getElementsByClassName').
On the contrary, if I set the function with the property "onclick" directly on the element the function works perfectly. So I think the problem it's about referring to the calling object using e.target
Update 1
First of all, I want to say that this is a project for university and I cannot publish the whole code, it would be risky for my exam.
Then there are more issues apparently. First of all with the method getElementsByClassName() applied on document it seems that he can get the Collection of Elements but then if I try to print the single Element it gives me undefined on the log. Here's the code:
var list = document.getElementsByClassName("prova");
if (list[0]) {
console.log("Assigning using \"list[0]\" as check");
list[0].onclick = espandi();
list[0].addEventListener("click",espandi);
console.log("finished adding listeners");
}
else if(list.item(0)){
console.log("Assigning using \"list.item(0)\" as check");
list.item(0).onclick = espandi();
list.item(0).addEventListener("click",espandi);
console.log("finished adding listeners");
}
else console.log("failed assignment");
console.log("printing list");
console.log(list);
console.log("printing list[0]");
console.log(list[0]);
console.log("printing list.item(0)");
console.log(list.item(0));
and here's the log output:
log output
Apparently the only way I succesfully make my script work is editing the function this way:
function espandi (caller) {
var toHide = document.getElementsByClassName("optional");
for (var index = 0; index < toHide.length; index++)
toHide[index].style.display = "none";
var toShow = caller.getElementsByClassName("optional");
for (index = 0; index < toShow.length; index++)
toShow[index].style.display = "block";
}
and then assigning it to elements directly using the "onclick" HTML attribute, like this:
<table class="prova" onclick="espandi(this)">
so that the parameter "caller" refers to the element who actually triggered the function espandi. The problem is I really want to know 2 things:
how to refer to the caller using an EventHandler function (in the case of method .addEventListener()) and a normal function (in the case of the attribute .onclick of the desired element) in JS.
how to manage the method getElementByClassName() and the collection returned by itself.
In the end, just to sum up, now I have problems with assigning the event listeners and also with referring to the caller without using a parameter like this in the HTML code I showed you.
You are calling espandi instead of assign it to onclick handler.
So you need to remove the () and do expansibleObjects[index].onclick = espandi;
Anyway in your question I don't see any e.target.addEventListener() so when you say The fact is the line e.target.addEventListener() gets me an error I don't understand what you mean, maybe you have to add more code.

Can I use a property of an instance to update other properties?

I'm trying to update a property of a constructor based on other property values that are getting changed when a certain function fires.
I've tried to create a function as a property and I will still get the same result.
class Rps {
constructor () {
this.userChoice
this.appChoice
this.userPoints = 0
this.pcPoints = 0
this.score = `${this.userPoints} - ${this.pcPoints}`
console.log(score)
this.registeredChoice = []
}
}
After I call a function that increments the user and pc Points, the properties will be updated after i try to console.log() the new object but it will not be the same for the score. The value of the score will not change.
A getter is perfect for this:
class Rps {
constructor () {
this.userChoice
this.appChoice
this.userPoints = 0
this.pcPoints = 0
this.registeredChoice = []
}
get score() {
return `${this.userPoints} - ${this.pcPoints}`
}
}
Alternatively, don't just update properties of the object in that function you have, but call setUser(points) and setPc(points) methods that can update the score property.

How to define a variable that is undefined?

I have the following code:
if (!config.callers[uID].calls) {
console.log(config.callers[uID].calls);
config.callers[uID].calls = 0;
saveConfig();
console.log(config.callers[uID].calls);
}
Where I have a JSON file that is called config, and has a property callers which is a collection of user IDs, and each one has a property calls. saveConfig() is a function that saves the config file.
As you can see, I am checking if the calls property is undefined, and if true then it defines it at 0. I also tried defining it to different stuff but it didn't seem to work. It just stays undefined.
Try
if(!config.callers.hasOwnProperty("uID")) {
console.log(config.callers);
config.callers[uID] = {};
config.callers[uID].calls = 0;
saveConfig();
console.log(config.callers[uID].calls);
} else if(!config.callers[uID].hasOwnProperty("calls")) {
console.log(config.callers[uID]);
config.callers[uID].calls = 0;
saveConfig();
console.log(config.callers[uID].calls);
}

JavaScript Callback Errors or Doesn't Run

I'm working with an array of cells (in qualtrics surveys) and have tried to write a function called watchSet that you can pass a set of cells and a function to that watches the set of cells for any changes (keyups) and runs the function passed to it again whenever any of that set of cells are changed.
function watchSet(set, mathFunction) {
var setSize = set.length;
for (var i=0; i < setSize; i++) {
set[i].down().observe("keyup", function(){
mathFunction
});
}
}
An example function that uses this is the qualtricsSum function (which also uses the mathSum function)
function mathSum(set, output) {
var setTotal = 0;
for (var j=0; j < (set.length); j++) {
var setInputValue = parseInt(set[j].down().value, 10);
if (isNaN(setInputValue)) { setInputValue = 0; }
setTotal = setTotal + setInputValue;
}
output.down().value = setTotal;
}
function qualtricsSum(array, output) {
watchSet(array, mathSum(array, output));
}
In the watchSet function I wrap the mathFunction I pass with function(){...} and it runs the mathSum function, but doesn't seem to run it on keyups, but if I don't wrap it with the unnamed function, I get Uncaught TypeError: Cannot read property 'call' of undefined as an error. I'm not sure if that's part of my problem.
When I manually run the for loop that's in watchSet and replace mathFunction with the function I intend to run, it does actually run the function I give it every time I edit the cells. This makes me think that somehow calling watchSet(set, mathFunction) and then referencing mathFunction in the function definition doesn't actually pass what I'm thinking it is passing.
EDIT:
I realized once I saw behtgod's answer that I didn't clarify this:
I do not always know what mathFunction's arguments look like, and I would like to be able to pass any function with any number of arguments as the mathFunction. Sometimes it will be functions with a format like mathSum(array, output), other times I'd like it to be mathEqual(array), or any number of different kinds of things.
First,your mathFunction is a function, so you should use it like
mathFunction();
Second,when below line is executed
watchSet(array, mathSum(array, output));
the mathSum have been called and only the result is pass to watchSet function.
So you should use like this:
function watchSet(set, mathFunction) {
var setSize = set.length;
for (var i=0; i < setSize; i++) {
set[i].down().observe("keyup", function(set,output){
mathFunction(set,output)
});
}
}
function mathSum(set, output) {
...
}
function qualtricsSum(array, output) {
watchSet(array, mathSum);
}
because you mathFunction is called in a callback ,so the arguments which the mathFunction used,must be arguments of the callback

how to get a property name which represent a function in JS

This is some JS code
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr)
{
window[methodName] = function()
{
console.log(methodName);
}
}
My problem is that how to get the name of a function in JS.
In JS, use this.callee.name.toString() can get the function name. But in this situation, it is a null value. How can i get the 'funName' string?
Sorry, I didn't make it clear.
I want to create functions in a for loop, all these functions has almost the same implementation which need its name. But others can call these functions use different name.I want to know what methodName function is called.
it seems a scope problem.
Try this:
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr) {
var methodName = methodArr[i]; // <---- this line missed in your code?
window[methodName] = (function(methodName) {
return function() {
console.log(methodName);
}
})(methodName);
}
window['secondFunc'](); // output: secondFunc

Categories

Resources