Automatically running a function inside an object when that object is called - javascript

I am building a text based choice RPG game using Javascript. I am able to add functions inside of an object and run them, however, I want the function to run if the option ( text node ) is chosen.
Currently, I declare a function, and then call it at the bottom of the page. The issue is, I want to function to run as soon as the choice is chosen.
Here is the code I have so far...
function addRadiatedStatus(){
character.radiated = true;
}
const textNodes = [
{
id: 1,
text: "Do you want to help this person?",
options: [
{
text: "Yes",
nextText: 2
},
{
text: "No",
nextText: 2
},
],
faction: "Greaser"
},
{
id: 2,
text: "It was a trap, do you run or kill them?",
options: [
{
text: "Run",
nextText: 3,
damage: 0,
},
{
text: "Kill",
nextText: 5,
damage: 8,
moneyDrop: 20,
radiationDamage: 2,
function: function update(){
if(character.greaser == true && textNodes[1].faction ==
"greaser"){
console.log("greaser check worked");
}
console.log("upadte function worked")
character.health -= this.damage;
character.cash += this.moneyDrop;
character.radiationLevel += this.radiationDamage;
character.maxHP -= this.radiationDamage;
if(this.radiationDamage >= 1 ){
addRadiatedStatus();
}
console.log("character HP" + " " + character.health);
console.log("character maxHP" + " " + character.maxHP);
console.log("moneyDrop " + " " + this.moneyDrop);
console.log("character cash" + " " + character.cash);
console.log("radiation level" + " " + character.radiationLevel);
console.log("character Raditated?" + " " + character.radiated);
}
}
],
faction: "Greaser",
}
]
textNodes[1].options[1].function();
I tried a few different things, including adding another key run: update() , run: this.update(), run: this.function, etc.
I am also a little confused because I thought that ES6 allows me to remove the function keyword, but that doesn't seem to be allowed ( I am probably just doing it wrong, or running into an issue based on how I set up my object ).
I am not sure how to go from calling textNodes[1].options[1].function to dynamically calling whichever function is nested within a specific choice option.
Thanks in advance for the help.

You can change this section to this:
update: (function(){
console.log("upadte function worked")
character.health -= this.damage;
character.cash += this.moneyDrop;
character.radiationLevel += this.radiationDamage;
character.maxHP -= this.radiationDamage;
if(this.radiationDamage >= 1 ){
addRadiatedStatus();
}
console.log("character HP" + " " + character.health);
console.log("character maxHP" + " " + character.maxHP);
console.log("moneyDrop " + " " + this.moneyDrop);
console.log("character cash" + " " + character.cash);
console.log("radiation level" + " " + character.radiationLevel);
console.log("character Raditated?" + " " + character.radiated);
});
The function keyword has been changed to update, then the function has been changed to an anonymous function ... You should refrain from using js keywords for your user-defined ones.
Then the anonymous function will not execute until you call it:
textNodes[1].options[1].update()
Here's an example of what I'm talking about:
This shows that you have to actually access the function and any other key for that matter for you to access the values.
var text = [
{
data1: "here",
data2: (function(){
return "You have to explicitly call me!"
})
}
]
console.log("Without calling any data: " + text[0])
console.log("When you call data2: " + text[0].data2())
console.log("Let us access data1: " + text[0].data1)

Related

Fetch array data (from JSON) using dynamic content in loop

This is a sample code I'm trying to build. The actual JSON has a lot more data making the "switch" statement portion of the code not very practical to maintain (currently the only way I could make it work).
Is there a way to replace it by something similar to what I used for the other data "Model1" & "Model2" to make use of dynamic data used in the "for" loop?
I created a test at: https://jsfiddle.net/ShaiHul/evrqj1b5/42/
var data = {
"Car": {
"wheels": 4,
"InStock": {
"Toyota": {
"Model1": 10,
"Model2": 5
},
"Honda": {
"Model1": 12,
"Model2": 3
}
}
},
"Bicycle": {
"wheels": 2,
"InStock": {
"Toyota": {
"Model1": 25,
"Model2": 14
},
"Honda": {
"Model1": 22,
"Model2": 13
}
}
}
};
var vehicles = [{
name: "Car"
},
{
name: "Bicycle"
}
];
for (i in vehicles) {
var vehicle = vehicles[i].name;
document.getElementsByClassName(vehicle + "Model1")[0].innerHTML = vehicle + ", Toyota, Model 1: " + data[vehicle].InStock.Toyota["Model1"];
document.getElementsByClassName(vehicle + "Model2")[0].innerHTML = vehicle + ", Toyota, Model 2: " + data[vehicle].InStock.Toyota["Model2"];
switch (vehicle) {
case "Car":
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML = vehicle + ", Toyota, Wheels: " + data.Car["wheels"];
break;
case "Bicycle":
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML = vehicle + ", Toyota, Wheels: " + data.Bicycle["wheels"];
break;
}
}
<div class="CarModel1"></div>
<div class="CarModel2"></div>
<div class="CarWheels"></div>
<br/>
<div class="BicycleModel1"></div>
<div class="BicycleModel2"></div>
<div class="BicycleWheels"></div>
You can use nested Object.entries() and loop through them like this to get any dynamic data at any position:
var data={"Car":{"wheels":4,"InStock":{"Toyota":{"Model1":10,"Model2":5},"Honda":{"Model1":12,"Model2":3}}},"Bicycle":{"wheels":2,"InStock":{"Toyota":{"Model1":25,"Model2":14},"Honda":{"Model1":22,"Model2":13}}}};
const $vehicles = document.getElementById("vehicles");
Object.entries(data).forEach(([key, value]) => {
Object.entries(value.InStock).forEach(([vehicleName, models]) => {
Object.entries(models).forEach(([modelName, count], index) => {
$vehicles.innerHTML += `<div>${key}, ${vehicleName}, Model ${index + 1}: ${count}</div>`
});
$vehicles.innerHTML += `<div>${key}, ${vehicleName}, Wheels: ${value.wheels}</div>`;
});
$vehicles.innerHTML += '<br>' // add a line between vehicle types
});
<div id="vehicles">
</div>
I'm using template literals to create the content of each div. You can create it using + on each string if it's not supported in your browser yet.
Like this:
$vehicles.innerHTML += '<div>' + key + ', ' + vehicleName + ', Model ' + (index + 1) + ':' + count + '</div>';
Here's the updated fiddle
Updated fiddle without using template literals
Sure thing! Your switch statement can go from this:
switch (vehicle) {
case "Car":
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML = vehicle + ", Toyota, Wheels: " + data.Car["wheels"];
break;
case "Bicycle":
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML = vehicle + ", Toyota, Wheels: " + data.Bicycle["wheels"];
break;
}
to this:
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML =
vehicle + ", Toyota, Wheels: " + data[vehicle]["wheels"];
The key part in this new form is the data[vehicle]["wheels"] section, at the very end. Instead of using known object properties Car and Wheel, just use the variable vehicle which should be set to the string Car or Bicycle, which are also the property names in the json data you have at the top of your question.
So your entire for-loop would just look like this in the end:
for (i in vehicles) {
var vehicle = vehicles[i].name;
document.getElementsByClassName(vehicle + "Model1")[0].innerHTML = vehicle + ", Toyota, Model 1: " + data[vehicle].InStock.Toyota["Model1"];
document.getElementsByClassName(vehicle + "Model2")[0].innerHTML = vehicle + ", Toyota, Model 2: " + data[vehicle].InStock.Toyota["Model2"];
// new line, replacing your switch statement
document.getElementsByClassName(vehicle + "Wheels")[0].innerHTML =
vehicle + ", Toyota, Wheels: " + data[vehicle]["wheels"];
}

Trying to get this string to appear in a paragraph

Trying to get this string I have in JavaScript to appear in a paragraph in my HTML page by mousing over another paragraph.
function showInfo()
{
for (i = 0; i < object2; i = i + 1)
{
var myParagraph = "Name of Business: " + info.insurance[i].name + "\nState: " + info.insurance[i].state + "\nDiscount: " + info.insurance[i].discount + "\n" + "(" + i + 1 + "of" + object2 + ")"
}
}
myDiscount.addEventListener("mouseover", showInfo, false);
myDiscount.addEventListener("mouseout", showInfo, false);
<p id="discount">Show me the discounts!</p>
<p id="myP"></p>
If you want to show the next element of the info.insurance array each time you mouse over the paragraph, you shouldn't be using a for loop. That will do it all at once, not once for each mouseover. You need to put the counter in a global variable, and just increment it each time you call the function.
Yuo show it by assigning it to the innerHTML of the paragraph. You also need to use <br> rather than \n to make newlines (unless the style of the paragraph is pre).
var insurance_counter = 0;
function showInfo() {
var myParagraph = "Name of Business: " + info.insurance[insurance_counter].name + "<br>State: " + info.insurance[insurance_counter].state + "<br>Discount: " + info.insurance[insurance_counter].discount + "<br>(" + (insurance_counter + 1) + "of" + object2 + ")";
document.getElementById("myP").innerHTML = myParagraph;
insurance_counter++;
if (insurance_counter >= object2) { // wrap around when limit reached
insurance_counter = 0;
}
}

Vue.js mounted function runs too early

Essentially what I am trying to do is to run a a function that adds up different variables and sets a new one its pretty simple:
addup: function () {
this.homeScore1 = this.m1g1h + this.m1g2h + this.m1g3h + this.m1g4h + this.m2g1h + this.m2g2h + this.m2g3h + this.m2g4h;
this.awayScore1 = this.m1g1a + this.m1g2a + this.m1g3a + this.m1g4a + this.m2g1a + this.m2g2a + this.m2g3a + this.m2g4a;
this.homeScore2 = this.m3g1h + this.m3g2h + this.m3g3h + this.m3g4h + this.m4g1h + this.m4g2h + this.m4g3h + this.m4g4h;
this.awayScore2 = this.m3g1a + this.m3g2a + this.m3g3a + this.m3g4a + this.m4g1a + this.m4g2a + this.m4g3a + this.m4g4a;
this.hdoubles = this.m5g1h + this.m5g2h + this.m5g3h + this.m5g4h;
this.adoubles = this.m5g1a + this.m5g2a + this.m5g3a + this.m5g4a;
alert(this.m1g1h);
//total handicap is set here
this.hhandicap = this.singlesHHandicap + this.doublesHHandicap;
this.ahandicap = this.singlesAHandicap + this.doublesAHandicap;
//total score is calculated here
this.homescore = this.homeScore1 + this.homeScore2 + this.hdoubles + this.hhandicap;
this.awayscore = this.awayScore1 + this.awayScore2 + this.adoubles +this.ahandicap;
},
the value of this.m1g1h for example is set in a function called this.updatesSinglesScores(); that is run on page creation, It calls my databse and assignes the values returned to some vue variables:
created: function () {
this.updatesSinglesScores();
this.updateDoublesScores();
},
afterwards I call the addup function on mounted:
mounted: function () {
this.addup();
}
So the problem I am having is that the variable this.homeScore1 for example, that is being displayed in the html of the page does not chnages it remains to 0. Upon further inspection with the alert in the addup function I learned that this.m1g1h remains 0, even though it should be another value. Furthermore if I run the addup function with a button everything works fine. So could some one explain to me why this.m1g1h remains 0? also why does the addup function work when called from a button?

is there a way to get info from a variable that is defined inside a function?

I am trying to figure out if there is a way to access the information stored inside a variable that I defined inside a function? I am kinda confused on how to do what I am trying to do here...
note: this isn't the full code, but the piece of the code I need help with.
let question1 = new Question("What is California State Flower?", "1. Rose. 2. Tulip. 3. Poppy");
firstQuestion();
function firstQuestion(){
let someAnswer = prompt(question1.questionName + " " + question1.questionString);
}
if (someAnswer == "poppy"){
I am trying to use the if statement to figure out if a question answer is correct, but I can't do that because someAnswer was defined inside the function.... and i'm not sure if there is a way to do this without using a function?
Update:
Ok, I got that piece working, but now my code's if/else statement isn't working. if i put in the wrong answer, it says I have the right answer. I don't really see any logical reason for that...
//store score total
let pointsCount = 0;
//questions
class Question {
questionName: string;
questionString: string;
constructor(questionName:string, questionString:string){
this.questionName = questionName;
this.questionString = questionString;
}
}
//question one
let question1 = new Question("What is the California State Flower?", "1. Rose. 2. Tulip. 3. Poppy.");
let firstAnswer = firstQuestion();
function firstQuestion(){
return prompt(question1.questionName + " " + question1.questionString);
}
if (firstAnswer === "Poppy" || "poppy"){
pointsCount ++;
alert("You got it!" + " " + "You now have" + " " + pointsCount + " " + "points!");
} else {
alert("Wrong!" + " " + "You now have" + " " + pointsCount + " " + "points!");
}
//question two
let question2 = new Question("What is the California State Bird?","1. Quail. 2. Eagle. 3. Penguin.")
let secondAnswer = secondQuestion();
function secondQuestion(){
return prompt(question2.questionName + " " + question2.questionString);
}
if (secondAnswer === "quail" || "Quail"){
pointsCount++;
alert("You got it!" + " " + "You now have" + " " + pointsCount + " " + "points!");
} else if (secondAnswer !== "quail" || "Quail") {
alert("Wrong!" + " " + "You now have" + " " + pointsCount + " " + "points!");
}
You're close; you're not returning anything from your firstQuestion function, so nothing's ever really going to happen when you run this.
let question1 = new Question("What is California State Flower?", "1. Rose. 2. Tulip. 3. Poppy");
let answer = firstQuestion();
function firstQuestion(){
// return whatever the user enters in the prompt
return prompt(question1.questionName + " " + question1.questionString);
}
if (answer.toLowerCase() == "poppy"){
// call .toLowerCase on your answer to ensure you've covered capitalization edge-cases
}
Maybe this is what you need
let someAnswer;
function firstQuestion(){
someAnswer = prompt(question1.questionName + " " + question1.questionString);
}

How to choose what argument a variable is assigned to in a function? -Javascript

Given a normal function as such;
function descriptions(awesome, cool, alright){
return (awesome || "no one") + " is awesome. " + cool + " is cool. " +
+ alright + " is alright";
}
descriptions("jane", "jack", "jefferson");
//returns "jane is awesome. jack is cool. jefferson is alright."
I would like to use the same function, but would only like to pass it the final two arguments like so:
descriptions(cool : "john", alright : "jane"); //I would like a statement similar to this that works.
//should return "no one is awesome. jack is cool. jefferson is alright."
How would the above be done?
Something different syntactically but similar semantically might be achieved using object destructuring
function descriptions({ awesome = 'no one', cool, alright }) {
return awesome + " is awesome. " + cool + " is cool. " +
+ alright + " is alright";
}
Then you just invoke it with an object with corresponding properties:
descriptions({ cool: 'a', alright: 'b'});
You can do this by passing an object:
function descriptions(info) {
// Avoid TypeError if no argument is passed
if (!info) {
info = {};
}
return (info.awesome || "no one") + " is awesome. " + (info.cool || "no one") + " is cool. " + (info.alright || "no one") + " is alright.";
}
// Use:
console.log(descriptions({
awesome: "Strong Bad",
cool: "The Cheat",
alright: "Strong Sad"
}));
Yes you can certainly achieve this!
You can use a clever trick many developers use to set a variable to a default value if one is not provided.
function descriptions(awesome, cool, alright){
awesome = awesome || "";
if (awesome === "")
{
return "no one" + " is awesome. " + cool + " is cool. " +
+ alright + " is alright";
}
else{
return awesome + " is awesome. " + cool + " is cool. " +
+ alright + " is alright";
}
}
console.log(descriptions(undefined, "jack", "jefferson"));
Here is the working code. You could also pass an empty string.
In ECMAScript 6, this can sort of be done if you change your parameters to receive an object and take advantage of destructuring assignment.
function descriptions({awesome: awesome = "no one", cool: cool = "", alright: alright = ""} = {}) {
return awesome + " is awesome. " +
cool + " is cool. " +
alright + " is alright";
}
var res = descriptions({ cool: "john", alright: "jane" });
document.body.textContent = res;
So we have someone of an emulation of named parameters. Only thing extra needed by the caller is the curly braces.
Of course browser support is limited, but transpilers are available.
You could use a different approach:
var coolLevels = {
isCool: ["Jack", "John"]
, isAlright: ["Jane", "Jefferson"]
, isAwesome: []
}
function describe(people, coolLevel, phrase) {
return people.filter(function(person){
return Boolean(coolLevel.indexOf(person))
}).join(", ") + phrase
}
function descriptions(people){
var awesome = describe(people, coolLevels.isAwesome, ' is awesome.')
var cool = describe(people, coolLevels.isCool, ' is cool.')
var alright = describe(people, coolLevels.isCool, ' is alright.')
return awesome + cool + alright
}
demo: https://jsbin.com/kahawuhelu/edit?js,console,output
That is not possible in any variety of ECMAScript (including JavaScript).
It is theoretically possible to do things like use conditional, custom logic:
function(a,b,c){
if(arguments.length === 1) {
// we're in object mode;
b = a.b
c = a.c
a = a.a || 'default';
}
}
But that is not a built in part of the language.
This is NOT possible, for example:
function foo(a,b,c){return a/(b || 1) + c;}
foo({c:1,b:2,a:3})
There is also the possibility to conditionally define values based on number of arguments:
function say (a,b,c) {
if(arguments.length === 2) {
c = b;
b = a;
a = 'cat';
}
console.log('a ' + a + ' likes a ' + b + ' and a ' + c)
}
say('dog', 'bone', 'walk') // a dog likes a bone and a walk
say('mouse', 'bowl of milk') // a cat likes a mouse and a bowl of milk
You can pass undefined, null or "" as the first parameter. E.g:
descriptions(null, "jack", "jefferson");
Since you already use awesome || "no one", any falsy value will be good enough.
Another approach would be changing the function to receive an object:
function descriptions(options) {
return (options.awesome || "no one") + " is awesome. " + options.cool + " is cool. " +
options.alright + " is alright";
}
descriptions({ cool: "jack", alright: "jefferson" });
Now, depending on your browser support, you can use ES6 destructuring parameters:
const descriptions = ({ awesome = 'no one', cool, alright }) => (
`${awesome} is awesome. ${cool} is cool. ${alright} is alright`
);
descriptions({ cool: 'jack', alright: 'jefferson' });

Categories

Resources