Custom object 'game' doesn't have specified method - javascript

I'm trying to call a method cardSelection() from a function game() but instead I'm getting an error report which throws back to me the whole function with a "has no method cardSelection()" The idea is to access the method through the click of a button, which HTML tag is as follows:
<img id="PlayerCard0" class="card" src="images/Cards/Mario.png" alt="Mario" title="Mario" onclick="game.cardSelection('PlayerCard0')">
I'm not posting the whole Javascript as I believe this to be the case of a mere declaration error, anyhow, game() and cardSelection() were declared as follows:
function game()
{
...
this.cardSelection = function(card)
{
var cardElem = document.getElementById(card);
var id = cardElem.getAttribute("id");
var call = document.getElementById("call");
var select = function(card)
{
var found = 0;
for (var card = 0, totalCards = 5; card < totalCards; card++)
{
if (document.getElementById("PlayerCard" + card + "selected"))
{found++}
}
if (found == 0)
{
call.setAttribute("onclick", "changeHand()");
call.childNodes[0].nodeValue = "Change";
}
if (found < 3)
{
id += "selected"
setAttributes(cardElem,
{
"id" : id,
"style": "position: relative; top: 1em;",
"onclick" : "cardSelection('" + id + "')"
});
}
else { return; }
}
var unselect = function (card)
{
cardElem.removeAttribute("style");
id = id.replace("selected","");
setAttributes(cardElem,
{
"id" : id,
"onclick" : "cardSelection('" + id + "')"
});
var cardNumber = 0;
var found = false;
while (cardNumber < 5 && !found)
{
if (document.getElementById("playerCard" + cardNumber + "selected"))
{found = true;}
cardNumber++;
}
if (!found)
{
call.setAttribute("onclick", "compareHands()");
call.childNodes[0].nodeValue = "Hold";
}
}
if (id.indexOf("selected") >= 0){unselect(card);}
else {select(card);}
}
...
}
How game() is called:
window.onload = function openingScreen()
{
var startGame = document.createElement("a");
startGame.setAttribute("onclick", "game()");
startGame.appendChild(document.createTextNode("Play"));
window.table = document.getElementById("table");
table.appendChild(startGame);
}

The problem you are experiencing is the result of confusion about Objects/Classes/Instances in javascript.
The critical point for you on this issue is the difference between new game() and game();
var foo = new game()
tells the JS engine to create a new object
point that object's Prototype (not prototype) at game's prototype
and then invoke the function game, but for the sake of the body of that function this will refer to the created object.
If the function doesn't return an object, assign our created object to foo (otherwise assign the function's return value to foo
Inside the body of your game function, you have this.cardSelection = function (....
If you simply invoke game as a function, so just game(), without the new keyword, this inside the body of the function will be the window object! So you'll add cardSelection to the window object.
Also importantly: game.cardSelection() is looking for a function named cardSelection as a property on the function game.
Here's an example of using that style that would work:
var foo = function () {
//do interesting stuff
}
foo.bar = function () {
//do interesting stuff related to foo
}
foo.bar();
What you seem to be expecting would need to be written this way:
var game = function () {
this.cardSelection = function () {
//perform card selection!
}
}
var aGame = new game();
aGame.cardSelection();
Or, if cardSelection does not need access to any private properties of the game, it could be written more efficiently as
var game = function () {
//setup the game
};
game.prototype.cardSelection = function () {
//perform card selection
};
var aGame = new game();
aGame.cardSelection();

Related

Javascript Get Prototype Function Name

Disclaimer: This code was written by another developer, previously on the project and I can't change it - I'm not allowed too.
What I'm trying to do is get the name of the parent(?) function within this.foobar() from BaseDialog.
Is it possible?
var BaseDialog = new function () {
this.foobar = function () {
// get the prototype function name that called me? E.g DialogOne
}
}
DialogOne.prototype = BaseDialog;
function DialogOne() {
this.foobar();
}
DialogTwo.prototype = BaseDialog;
function DialogTwo() {
this.foobar();
}
let callerName = arguments.callee.caller.name.toString();
console.log("caller is " + callerName );

Can not use class in a function as a parameter (JScript)

I am trying to do a small JavaScript Lab. In the lab, first I created an Animal object :
function Animal(species, nature) {
this.species = species;
this.nature = nature;
var preys = new Array();
Animal.prototype.getSpecies = function() {
return species;
}
Animal.prototype.getNature = function() {
return nature;
}
Animal.prototype.getPreys = function () {
return preys;
}
Animal.prototype.setNature = function (newNature) {
nature = newNature;
}
Animal.prototype.setSpecies = function (newSpecies) {
species = newSpecies;
}
Animal.prototype.setPrey = function (newPreys) {
preys = newPreys;
}
}
Then, I created a World object which will basically store a number of animal object and separate them according to their nature.
/// <reference path="Animal.js" />
function World() {
var animals = new Array();
animals.push(new Animal("Wolf", "Carnivore"));
animals.push(new Animal("Crocodile", "Carnivore"));
animals.push(new Animal("Sheep", "Omnivore"));
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores());
}
function getOmnivores(animal) {
}
}
In my getOmnivors function, I can not use the Animal class as a variable. It is a little bit complicated for me cause I am new in JavaScript and regardless of their types we are using var keyword (Or not using in some places such as parameters in functions).
What did I do wrong and how can I fix it? I could not reach the Animal class in my private function getOmnivores. I think program does not understand that it is the class called Animal
I hope I explained well. Have a nice day!
EDIT
Error picture :
Animal is the Class name, you don't need it there. When using filter each element of the array is automatically passed on to the callback function as the first parameter of that function.
Since each element of the array is an instance of the class Animal you can use it straight away.
Also, the syntax {ClassName}.Prototype.{functionName} should not be used within that same Class, because by the time the interpreter reaches that line the Animal Class has not yet been defined. That syntax is used on already existing and defined classes. Use this.{functionName} instead.
function Animal(species, nature) {
this.species = species;
this.nature = nature;
this.preys = new Array();
this.getSpecies = function() {
return this.species;
}
this.getNature = function() {
return this.nature;
}
this.getPreys = function () {
return this.preys;
}
this.setNature = function (newNature) {
this.nature = newNature;
}
this.setSpecies = function (newSpecies) {
this.species = newSpecies;
}
this.setPrey = function (newPreys) {
this.preys = newPreys;
}
}
function World() {
var animals = new Array();
animals.push(new Animal("Wolf", "Carnivore"));
animals.push(new Animal("Crocodile", "Carnivore"));
animals.push(new Animal("Sheep", "Omnivore"));
this.getOmnivores = function () {
return animals.filter(this.filterOmnivores);
}
this.filterOmnivores= function(animal) {
return animal.getNature()=='Omnivore';
}
}
myworld = new World();
console.log(myworld.getOmnivores());
A working fiddle at https://jsfiddle.net/47dyg1q9/
The filter method takes a function as a paramter.
You must provide the function but in your code you are instantly calling the function:
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores());
}
Remove the parentheses to provide just the function without calling it, or insert an anonymous function:
World.prototype.getOmnivores = function () {
return animals.filter(getOmnivores);
}
// or
World.prototype.getOmnivores = function () {
return animals.filter(function (animal) {
return animal.nature === "omnivore";
});
}
You need to pass the function as an argument, not what it returns.
return animals.filter(isOmnivore);
And isOmnivore becomes
function isOmnivore(animal) {
animal.nature == 'Omnivore';
}

Javascript: How can I select a functions internal properties via it's parameters

I have a function that creates a menu, it has some buttons assigned to it and accepts an args parameter. Part of the function is a method called setActiveButton. When I create a menu I would like to dictate which of the buttons is active by passing in an option args.
For example:
var createMenu = function (args) {
this.btnOne = new Button(); // construct a button
this.btnTwo = new Button();
this.btnTwo = new Button()
this.setActiveButton(args.desiredButton);
return this;
}
createMenu({ desiredButton: btnTwo });
How do I tell createMenu to use one of it's buttons via args? I can't pass in { desiredButton: this.btnTwo } - because at that point this.btnTwo is not defined.
I was thinking about passing in a string and then using conditional statements like this:
var createMenu = function (args) {
var buttonChoice;
this.btnOne = new Button();
this.btnTwo = new Button();
this.btnThree = new Button();
if (args.desiredButton === "button one") {
this.setActiveButton(this.btnOne);
}
if (args.desiredButton === "button two") {
this.setActiveButton(this.btnTwo);
}
if (args.desiredButton === "button three") {
this.setActiveButton(this.btnThree);
}
return this;
}
createMenu({ desiredButton: "button two" });
However, I feel that there should be a cleaner and more succinct way to do this.
What is your suggestion?
just pass the name of the button as a string, and access with brackets.
var createMenu = function (args) {
this.btnOne = new Button(); // construct a button
this.btnTwo = new Button();
this.btnTwo = new Button()
this.setActiveButton(this[args.desiredButton]); // access this[property]
return this;
}
createMenu({ desiredButton: 'btnTwo' }); // string name of property
It's a little unclear to me why you are returning an object of properties that have no values, but you could do it like this. In my example I set the properties equal to strings like 'button 1', 'button 2', etc:
// pass number of total buttons, index of active button
var createMenu = function (total, active) {
var obj = {};
for (var i = 0; i < total; i++) {
obj['btn'+(i+1)] = 'button '+(i+1);
}
setActiveButton(obj['btn'+active]);
return obj;
}
In your example you reference setActiveButton as a property of the function but it isn't defined, so I have referenced it as a separate function.

Javascript OOP new object

**** EDIT *****
using the answer bellow I have created a new function and put my object into it's prototype.
var mySlider = new Slider();
mySlider.init({.......})
but now when I try to call another function from within a function (this.animate) on my Slider.prototype all I get is
"Uncaught TypeError: Cannot read property '0' of undefined"
cant seem to work out how to call get other functions to work, I've amended my code bellow with my new code
*****/ EDIT *****
I've tried to create my own slider using dojo.
I have an HTML page with the content and at the end of the page I have a script to start my slider
dojo.ready(function () {
var mySlider = new Slider();
mySlider.init({
frameId: "#sliderFrame",
slideClass: ".slide",
sliderImgClass: ".sliderImage",
captionClass: ".caption",
thumbsClass: ".thumb",
seconds: 1
});
});
then on my external js file I have my code
function Slider() {}
Slider.prototype = {
//Initialize all Elements
init: function (object) {
this.sliderFrame = dojo.query(object.frameId);
this.slideContainers = this.sliderFrame.query(".slide");
this.slideImg = this.sliderFrame.query(object.sliderImgClass) || '';
this.SlideCaption = this.sliderFrame.query(object.captionClass) || '';
this.thumbs = this.sliderFrame.query(object.thumbsClass) || '';
this.numOfSlides = this.slideImg.length || 0;
this.hovering = false;
this.time = object.seconds * 1000 || 3000;
this.myInterval = '';
this.playing = 0;
this.start();
},
// Starts animation on slide 0
start: function () {
this.animate(this.playing);
this.initLoop(true);
this.listener(this.thumbs, this.sliderFrame);
},
//EventListener for mouse events
listener: function (theThumb, theFrame) {
theThumb.connect('onclick', this.clicked);
theFrame.connect('mouseenter', this.mouseOn);
theFrame.connect('mouseleave', this.mouseOff);
},
mouseOn: function () {
this.initLoop(false);
},
mouseOff: function () {
this.initLoop(true);
},
clicked: function (e) {
this.playing = this.getAttribute("data-slide");
this.animate(this.playing);
},
// start interval if true, otherwise clear
initLoop: function (act) {
if (act === true) {
this.myInterval = setInterval(this.loopSlides, this.time);
} else {
clearInterval(this.myInterval);
}
},
// interval resets loops through to end and back to zero
loopSlides: function () {
if (this.playing < this.numOfSlides - 1) {
this.playing++;
this.animate(this.playing);
} else {
this.playing = 0;
this.animate(this.playing);
}
},
//the animation which makes changes css to active slide 'e' || this.playing
animate: function (e) {
for (var ii = 0; ii < this.numOfSlides; ii++) {
this.slideContainers[ii].className = "slide";
this.thumbs[ii].className = "thumb";
this.slideImg[ii].className = "sliderImage";
this.SlideCaption[ii].className = "caption";
}
this.slideContainers[e].className = "slide active";
this.thumbs[e].className = "thumb active";
this.slideImg[e].className = "sliderImage active";
this.SlideCaption[e].className = "caption active";
}
};
The object works fine by it self and everything does as need be, I'm sure I could make it better.
What I'd like to do is have the mySlider set up with a "new" or "Object.create".
This is so I can have multiple Sliders on one page each becoming their own object.
I just can't get my script to run once I implement "new" or "Object.create" as my Slider needs to be a function not an object! :(
Cn anyone point me to a good pattern that I could use to implement what I'm trying to do.
I've gone through "essential js design patterns" but can't seem to find a pattern that fits.
Thanks in advance :)
Without Object.create()--just so you can understand instances--you would do:
function Slider() {};
Slider.prototype = {
init: function() {...}
// ...
};
var mySlider = new Slider();
mySlider.init(...);
Then inside the functions just be sure to use "this.whatever" instead of "Slider.whatever".
This is essentially the same effect as using Object.create().
oop in javascript is ugly. (at least until ES6 which supports the class and implements keywords) but even ES6 will not support multiple inheritance. I wrote a small class library (available on github) for javascript that makes creating classes and inheritance much easier to both develop and maintain. for example to create a class just do this:
ds.make.class({
type: 'a',
constructor: function (x) { this.val = x; },
mul: function (s) {
this.val *= s;
return this;
}
});
// now to inherit class a just do this...
ds.make.class({
type: 'b',
inherits: a,
constructor: function (x) { this.val = x; },
sub: function (s) {
this.val -= s;
return this;
}
});
var o = new b(5);
var output = o.mul(3).sub(5).val; // output = 10

How do I run an object's method onEvent in javascript?

I just started using javascript and I'm missing something important in my knowledge. I was hoping you could help me fill in the gap.
So the script I'm trying to run is suppose to count the characters in a text field, and update a paragraph to tell the user how many characters they have typed. I have an object called charCounter. sourceId is the id of the text area to count characters in. statusId is the id of the paragraph to update everytime a key is pressed.
function charCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
}
There is one method called updateAll. It updates the count of characters and updates the paragraph.
charCounter.prototype.updateAll = function() {
//get the character count;
//change the paragraph;
}
I have a start function that is called when the window loads.
function start() {
//This is the problem
document.getElementbyId('mytextfield').onkeydown = myCounter.updateAll;
document.getElementbyId('mytextfield').onkeyup = myCounter.updateAll;
}
myCounter = new charCounter("mytextfield","charcount");
window.onload = start;
The above code is the problem. Why in the world can't I call the myCounter.updateAll method when the event is fired? This is really confusing to me. I understand that if you call a method likeThis() you'll get a value from the function. If you call it likeThis you are getting a pointer to a function. I'm pointing my event to a function. I've also tried calling the function straight up and it works just fine, but it will not work when the event is fired.
What am I missing?
Thanks for all the answers. Here's three different implementations.
Implementation 1
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+this.count+" charactors";
};
function start() {
myCharCounter.updateAll();
document.getElementById('mytextfield').onkeyup = function() { myCharCounter.updateAll(); };
document.getElementById('mytextfield').onkeydown = function() { myCharCounter.updateAll(); };
};
myCharCounter = new CharCounter('mytextfield','charcount');
window.onload = start;
Implementation 2
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+ this.count+" charactors";
};
CharCounter.prototype.start = function() {
var instance = this;
instance.updateAll();
document.getElementById(this.sourceId).onkeyup = function() {
instance.updateAll();
};
document.getElementById(this.sourceId).onkeydown = function() {
instance.updateAll();
};
};
window.onload = function() {
var myCounter = new CharCounter("mytextfield","charcount");
myCounter.start();
};
Implementation 3
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
};
CharCounter.prototype.updateAll = function() {
this.count = document.getElementById(this.sourceId).value.length;
document.getElementById(this.statusId).innerHTML = "There are "+this.count+" charactors";
};
function bind(funcToCall, desiredThisValue) {
return function() { funcToCall.apply(desiredThisValue); };
};
function start() {
myCharCounter.updateAll();
document.getElementById('mytextfield').onkeyup = bind(myCharCounter.updateAll, myCharCounter);
document.getElementById('mytextfield').onkeydown = bind(myCharCounter.updateAll, myCharCounter);
};
myCharCounter = new CharCounter('mytextfield','charcount');
window.onload = start;
I think you are having problems accessing your instance members on the updateAll function, since you are using it as an event handler, the context (the this keyword) is the DOM element that triggered the event, not your CharCounter object instance.
You could do something like this:
function CharCounter(sourceId, statusId) {
this.sourceId = sourceId;
this.statusId = statusId;
this.count = 0;
}
CharCounter.prototype.updateAll = function() {
var text = document.getElementById(this.sourceId).value;
document.getElementById(this.statusId).innerHTML = text.length;
};
CharCounter.prototype.start = function() {
// event binding
var instance = this; // store the current context
document.getElementById(this.sourceId).onkeyup = function () {
instance.updateAll(); // use 'instance' because in event handlers
// the 'this' keyword refers to the DOM element.
};
}
window.onload = function () {
var myCharCounter = new CharCounter('textarea1', 'status');
myCharCounter.start();
};
Check the above example running here.
The expression "myCounter.updateAll" merely returns a reference to the function object bound to "updateAll". There's nothing special about that reference - specifically, nothing "remembers" that the reference came from a property of your "myCounter" object.
You can write a function that takes a function as an argument and returns a new function that's built specifically to run your function with a specific object as the "this" pointer. Lots of libraries have a routine like this; see for example the "functional.js" library and its "bind" function. Here's a real simple version:
function bind(funcToCall, desiredThisValue) {
return function() { funcToCall.apply(desiredThisValue); };
}
Now you can write:
document.getElementById('myTextField').onkeydown = bind(myCounter.updateAll, myCounter);
You can:
function start() {
//This is the problem
document.getElementbyId('mytextfield').onkeydown = function() { myCounter.updateAll(); };
document.getElementbyId('mytextfield').onkeyup = function() { myCounter.updateAll(); };
}
In ASP.Net Ajax you can use
Function.createDelegate(myObject, myFunction);
I want to do something like this but simpler.
The idea is to have the user click on bolded text and have a text field appear where they can change all the values of a role-playing character. Then when the value is changed, have the text field disappear again replaced by the updated bolded text value.
I can do this already using an annoying text box alert. But I would rather have something similar to this below to replace all that.
I have searched for months and CMS is the closest to answering my question in the simplest way with a full html example. Nobody else on the net could.
So my question is, how do I do this?
I have multiple objects(characters) and need this.elementId to make this work.
I've modified this example but it breaks if I try to add to it.
html>
head>
title>Sandbox
/head>
body>
input id="textarea1" size=10 type=text>
script>
function CharCounter(sourceId, statusId)
{this.sourceId=sourceId;
this.statusId=statusId;
this.count=0;
}
CharCounter.prototype.updateAll=function()
{text=document.getElementById(this.sourceId).value
document.getElementById(this.statusId).innerHTML=text
}
CharCounter.prototype.start=function()
{instance=this
document.getElementById(this.sourceId).onkeyup=function ()
{instance.updateAll()}
}
window.onload=function ()
{myCharCounter=new CharCounter('textarea1', 'status')
myCharCounter.start()
}
/script>
/body>
/html>

Categories