Iterating through dictionary inside class object in JavaScript - javascript

I have a class:
class Quizer {
// construct new quiz for unique user
constructor(quizObj) {
this.quiz = quizObj;
this.currentQuestionNum = 0;
this.userSelections = [];
}
...
buttonAction(setup) {
//var text = this.quiz.question1.question; <-- //works
var text = this.quiz[currentQuestionNum].question; // doesnt work
}
}
That is constructed here:
var quiz = new Quizer(questionObjects);
Where questionObjects is:
var questionObjects = {
question1: {
question: "Darwin explained his theory of evolution in a book called?",
choices: [
"this is the correct answer, choose me!",
"On the Origin of Species",
"Survival of the Fittest"
],
correctAnswer: "On the Origin of Species"
},
question2: {
...
}
}
In buttonAction, my goal is to iterate through questionObjects and get each question. Can someone help me with the syntax?

You need something like this
for(var key in questionObjects){
// The following gives you the question for the current key
questionsObjects[key].question
}
As it is stated here:
The for...in statement iterates over the enumerable properties of an
object, in arbitrary order. For each distinct property, statements can
be executed.

Related

How to work on dynamic properties of an array of objects in javascript? [duplicate]

If I have a JSON object like this:
{
"message": {
"name": { "stringLengthTooShort": "blub" }
}
}
The name of the property (here) stringLengthTooShort is changing every time,
how could I simply just get the child property of name with JS?
At the moment I have message.name but how could I get now the child of it?
if it's always the first property of message.name, you could do something like:
var keys = [];
for (var l in message.name) {
if (message.name.hasOwnProperty(l)){
keys.push(l);
}
}
//=>first property value should now be in message.name[keys[0]]);
// (its label is keys[0])
Edit: nine years after this answer all modern browsers support es20xx, so it's safe to use:
const obj = {
"message": {
"name": { "stringLengthTooShort": "blub" }
}
};
console.log(Object.keys(obj.message.name)[0]);

Can I refresh the values of (an array of) objects as the variable they refer to changes?

I am trying to make a generator of simple sentences by combining data from two arrays. One array has the nouns/subjects and the other the verbs/actions.
Obviously, some nouns are singular and some plural. To make this work, I make the nouns objects (and a class), eg: { txt: "Jason", snglr: true }, { txt: "The kids" }.
Then, I create a function that forms the verb according to whether the noun is singular or plural (snglr: true or false/undefined) and apply it as a method of the noun class.
I call the method from within the string of the verb/action, as in: { txt: `${curr_noun.verb("go", "goes")} to music class.`}
My problem is that all the verbs get their values from the first noun used. When I change the noun, the verbs still refer to the plural or singular form called by the first noun.
Is there a way to refresh the actions objects, so that each time their values refer to the current noun?
(Or if I'm totally missing an easier way, can you please let me know?)
Thanks. Here is the whole code:
class noun {
constructor(text, singular) {
this.txt = text; // The subject of the sentence
this.snglr = singular; // Whether the subject is singular (true) or plural (undefined/false)
this.verb = function (plur, sing) { //this function is called from within the string containing the verb (see "actions" array, below)
if (sing == undefined) { // for regular verbs, we call it with one argument, eg. .verb("walk"), it creates "walks" by adding "s."
sing = plur + "s";
}
if (this.snglr) { // for irregular verbs, we call it with two arguments, eg. .verb("go", "goes")
return sing;
} else {
return plur;
}
}
}
}
var curr_noun = {};
var nouns = [new noun("Jason", true), new noun("The kids")];
curr_noun = nouns[0]; // We pick "Jason" as the sentence's subject.
var actions = [
{ txt: `${curr_noun.verb("go", "goes")} to music class.`},
{ txt: `${curr_noun.verb("visit")} London.`}
];
curr_action = actions[1];
console.log(`${curr_noun.txt} ${curr_action.txt}`);
// All good, so far.
// My problem is that the above values of actions[0].txt and actions[1].txt are given based on Jason.
// When I later change the curr_noun to "The kids," I still get singular verb forms.
curr_noun = nouns[1];
curr_action = actions[0];
curr_noun.verb();
console.log(`${curr_noun.txt} ${curr_action.txt}`);
I think we could simplify this code a bit. You could create a function to create the sentences. This function would take a noun object and verb object and the grammatical object which is a string.
This way we can remove the class and reduce the number of lines that we write. With this approach, we can also ensure the nouns and verbs match in terms of plurality. Here is an example:
const nouns = [
{
text: 'Jason',
isSingular: true,
},
{
text: 'The kids',
isSingular: false,
},
];
// in grammar, the noun at the end of the sentence is called object
const verbs = [
{
// "to" is actually part of the verb here(prepositional verb)
singular: 'goes to',
plural: 'go to',
},
{
singular: 'visits',
plural: 'visit',
},
];
// in grammar, the noun at the end of the sentence is called object
const objects = ['music class.', 'London.'];
const createSentence = (noun, verb, object) => {
const myVerb = noun.isSingular === true ? verb.singular : verb.plural;
return `${noun.text} ${myVerb} ${object}`;
};
console.log(createSentence(nouns[0], verbs[1], objects[1]));
console.log(createSentence(nouns[1], verbs[0], objects[0]));
Note: I am not saying that this is how it should be done, but just pointing out where the problem is.
You define your var actions based on curr_noun = nouns[1];, i.e. "Jason", here:
var actions = [
{ txt: `${curr_noun.verb("go", "goes")} to music class.` },
{ txt: `${curr_noun.verb("visit")} London.` }
];
This never changes. So when referring to actions[0] later, they are still based on "Jason".Try to console.log(this.txt) inside the .verb-method to see where it goes wrong.
When reassigning them again to "The kids" before logging, it works fine:
curr_noun = nouns[1];
var actions = [
{ txt: `${curr_noun.verb("go", "goes")} to music class.` },
{ txt: `${curr_noun.verb("visit")} London.` }
];
curr_action = actions[0];
console.log(`${curr_noun.txt} ${curr_action.txt}`);
// -> The kids go to music class.

Remove element from named values in javascript

I have the following function, which is called when a google forms is submitted. I'm trying to concatenate all answers into a single array that's gonna be used latter:
function onFormSubmit(e) {
var respostas = e.namedValues;
for(item in respostas){
rp = rp.concat(respostas[item]);
}
}
But I would like to drop the timestamp that comes together with the answers. I can access it with respostas['Timestamp'], but I can't find a way to drop or ignore it. The documentation didn't help much.
var cp = [];
function onSubmitForm(e) {
var respostas = e.namedValues;
for (var name in respostas) {
if (respostas.hasOwnProperty(name) {
if (name !== 'Timestamp') {
cp.push(respostash[name]);
}
}
}
}
This is what I would suggest. Using concat to add an item is overkill, you can just push it. Also is a good practice when you are looping over object properties to make sure that they are its own properties of that object, not inherited from prototype. You can read more about it here
You can check the name of the property before concatenate it with the rest.
If the key item equals Timestamp (the undesired property) just skip the current loop.
for(item in respostas) {
if (item === 'Timestamp') {
continue;
}
rp = rp.concat(respostas[item]);
}
EDIT: Based on comments, OP attests that item in the for..in loop is a integer, but, unless his/her code differs radically from the docs, the variable should hold strings, not numbers.
var respostas = {
'First Name': ['Jane'],
'Timestamp': ['6/7/2015 20:54:13'],
'Last Name': ['Doe']
};
for(item in respostas) {
console.log(item);
}
e.namedValues returns a JSON Object with custom keys.
var jsonObj = e.namesValues;
/* e.namedValues returns data like this...
{
"test1": "testval1",
"test2": "testval2",
"test3": "testval3",
}
*/
for(item in respostas){
Logger.log(item); //Key
Logger.log(respostas[item]); //Value
}
This should let you access the key or value on the items in respostas.
The accepted answer is better as it does more to help the user to fix their exact problem, however, I will leave this here for future users in case they want to understand how to access the variables in the object that Google Apps Scripts returns.

Problems in accessing sub properties from separate JavaScript file

I was trying to access sub-properties from a javascript file and it's giving me something weird!
Suppose this is my JS file named data.js
module.exports = {
something: {
name: "Something",
num: 1,
email: "something#gmail.com"
},
somethingtwo: {
name: "Something Something",
num: 2,
email: "somethingtwo#gmail.com"
},
};
In my main js file named app.js, where I need to access it, it looks like
var persons = require('./data.js');
var getAName = function() {
for(var name in persons) {
console.log(name.email);
}
}
I really don't know what goes wrong but I have been trying this for quite a long time now. The expected output is the email Ids from the data.js file but instead, i get undefined times the number of entries (if there are 2 entries in data.js, then I get 2 undefine and so on).
How can I access the email or the num from the data.js without those undefines?
console.log(name) is returning something somethingtwo
Well, name.email is undefined because name is a string.
You can test that by writing
console.log(typeof name);
Now, to solve your problem, you need to access the property correctly:
var getAName = function() {
for (var name in persons) {
console.log(persons[name].email)
}
}
Returns:
something#gmail.com
somethingtwo#gmail.com
for(var name in persons) {
//persons is actually an object not array
//you are actually iterating through keys of an object
//var name represent a key in that object
console.log(persons[name]); //value corresponding to the key
}
I guess this code will give you the desired result.
You should be using console.log(persons[name].email)
require don't automatically calls the module
var DataArchive = require('./data.js');
var module = DataArchive.module;
var persons = module.exports;
var getAName = function() {
for(var person in persons) {
//person should be something (first iteration) and somethingtwo (second iteration)
console.log(person.email);
}

People guesser program with JavaScript objects

I'm trying to learn JavaScript, and so I'm doing this project to practice. I'm trying to figure out how the objects and all that work. Basically what I want, is a list of people, as objects, with certain properties assigned to each. Then it to ask a bunch of questions until it guesses the person you're thinking of. I've searched around, but can't really find exactly how to do this. This is what I have so far:
function person(name,age,eyecolor,gender,eyeglasses)
{
this.name=name;
this.age=age;
this.eyecolor=eyecolor;
this.gender=gender;
this.eyeglasses=eyeglasses;
}
var Dad=new person("Dad",45,"blue","male",true);
var Mom=new person("Mom",48,"blue","female",false);
var Brother=new person("Brother",16,"blue","male",false);
var Sister=new person("Sister",15,"green","female",false);
function askQuestion (){
}
function begin(){
askQuestion();
}
Now what I want is a way that I can, in the askQuestion function, select a question from a list based on what we know so far about the person. And then recalculate who of the people it could be, and then pick another question to ask, until we know who it is. Hopefully I've made this clear. How would I do that?
This is a bit like the game "Guess Who?" no? Alright so this is what you do:
First you create a constructor for a person. You got this right.
function Person(name, age, eyecolor, gender, eyeglasses) {
this.name = name;
this.age = age;
this.eyecolor = eyecolor;
this.gender = gender;
this.eyeglasses = eyeglasses;
}
Then you create list of possible people. A list means an array.
var people = [
new Person("Dad", 45, "blue", "male", true),
new Person("Mom", 48, "blue", "female", false),
new Person("Brother", 16, "blue", "male", false),
new Person("Sister", 15, "green", "female", false)
];
Then you keep asking questions to guess who the person is. To keep asking means to use a loop. We'll keep looping until there's only one person left in the list (the person we're looking for):
while (people.length > 1) askQuestion();
Next we define the askQuestion function. First we need to select what question to ask. So we make a list of questions. Again this is an array. We'll also store which property to test and the result for true and false conditions.
var questions = [
["eyecolor", "blue", "green", "Does the person have blue eyes?"],
["gender", "male", "female", "Is the person a male?"],
["eyeglasses", true, false, "Does the person wear eyeglasses?"]
];
These three questions are all you need to know to determine who the person is. Next we record which question is currently being asked (0, 1 or 2).
var question_no = 0;
Finally we ask the questions to determine who the person is:
function askQuestion() {
var question = questions[question_no++];
var answer = confirm(question[3]) ? question[1] : question[2];
var predicate = question[0];
people = people.filter(function (person) {
return person[predicate] === answer;
});
}
Here we ask the user a question, determine which answer he chose and use that information to filter the people who match the given description. Finally we end up with one person:
alert("The person you're thinking about is " + people[0].name + ".");
See the working demo here: http://jsfiddle.net/9g6XU/
Here's how I would do it. It's shorter than Aadit's answer, and in my opinion, simpler and easier to understand.
Make a list of the people. Use an array literal:
var people = [Dad, Mom, Brother, Sister];
I like to structure my code, so I would put the questions in an object:
var questions = {
"Are they male or female?" : 'gender',
"What is their eye color?" : 'eyecolor',
"Do they wear glasses?" : 'eyeglasses'
};
This could be expanded with as many properties as you want.
Then:
for (question in questions) { //This is how you loop through an object
var property = questions[question]; //This gets the second part of the object property, e.g. 'gender'
var answer = prompt(question);
//filter is an array method that removes items from the array when the function returns false.
//Object properties can be referenced with square brackets rather than periods. This means that it can work when the property name (such as 'gender') is saved as a string.
people = people.filter(function(person) { return person[property] == answer });
if (people.length == 1) {
alert("The person you are thinking of is " + people[0].name);
break;
}
if (people.length == 0) {
alert("There are no more people in the list :(");
break;
}
}
And I, too, made you a fiddle.Here it is.

Categories