Create objects dynamically with loop using JavaScript [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I was hoping someone could point me in the right direction.
I'm basically trying to build an OOP solution to dynamically generate a lot of objects based on a class and then to be able to run methods associated to each object via the class methods.
Below is my un-dynamic code.
// Create videoObject class
function videoObject(videoTag, videoNum){
this.videoTag = videoTag;
this.videoNum = videoNum;
this.videoTagHref = videoTag.attr("href");
this.videoId = function(videoTag){
};
this.addAttrId = function(videoNum){
};
this.printObjectInfo = function(videoId){
};
this.embedVideo = function(videoId, videoTag, videoNum){
};
this.buildControls = function(videoTag){
};
};
// Manually create two objects and run class methods
var newVideo1 = new videoObject($('.yt-player-0'), 0);
newVideo1.videoId();
newVideo1.addAttrId();
newVideo1.embedVideo();
newVideo1.buildControls();
var newVideo2 = new videoObject($('.yt-player-1'), 1);
newVideo2.videoId();
newVideo2.addAttrId();
newVideo2.embedVideo();
newVideo2.buildControls();
// I want to somehow create newVideo1 and newVideo2 dynamically inside a loop like below
var length = $('.yt-player').length;
for (var i = 0; i < length; i++) {
}
Any help you guys could give me would be much appreciated.
Thanks,
Tom

I would try this (untested):
// Create videoObject class
function videoObject(videoTag, videoNum){
this.videoTag = videoTag;
this.videoNum = videoNum;
this.videoTagHref = videoTag.attr("href");
this.videoId = function(videoTag){
};
this.addAttrId = function(videoNum){
};
this.printObjectInfo = function(videoId){
};
this.embedVideo = function(videoId, videoTag, videoNum){
};
this.buildControls = function(videoTag){
};
// call these methods in your constructor instead of repeatedly from elsewhere
this.videoId();
this.addAttrId();
this.embedVideo();
this.buildControls();
// send back a reference to this newly created video object to the loop
return this;
};
// create an array of video object references
var videoObjectReferences = [];
for (var i=0;i<10;i++){
// building ten video objects here, with ids of: yt-player-0, yt-player-1, etc.
// build a selector to reference them via id, not by class with a dot as you have in your question
var sel = String("#yt-player-" + i);
// create the object and store a reference to the video object so you can do something with it later
var newVid = new videoObject($(sel), i);
// build list of references
videoObjectReferences.push(newVid);
}

var videos = [2];
for(var i = 0; i < 2; i++){
videos[i] = new videoObject($('.yt-player-0'), 0);
/*Extra method calls here*/
}
If you always want to initialize your object with those extra method calls, you may want to consider having your object constructor handle that for you. Then your client code would be much cleaner.

Related

Putting an object into an array in JavaScript

I'm currently working with an MVC JS framework and I want to be able to get a list of objects that I can take a random entry out of on a loop. So far I've managed to create a function that finds a random ID and pulls out that object so that part is not a problem. It's what is going into the array of objects:
QuestionsSetup: function(gameType) {
// Setup Resources
var c = this.View.children;
var player1qs = [];
var leftQ = 0;
var rightQ = 0;
var maxQValue = 50;
var minQValue = 1;
// Fill array with questions
for (var i = 0; i < 5; i++) {
// Build a random question with numbers between 1 and 50
// Build Question Text to output to user
// Generate correct answers based on generated question
// Generate unsorted, incorrect answers and add them to an array
//Place Questions into object
questions.qId = i;
questions.leftQ = leftQ;
questions.rightQ = rightQ;
questions.correctAnswer = correctAnswer;
questions.allAnswers = sortedAnswers;
questions.questionText = questionText;
//Add to array of questions
player1qs.push(questions);
}
}
This does add them to an array but when adding a new object it also changes the values of the existing objects in the array so they all come out the same no matter which one I pull out later. The questions object is declared in it's own file in a models folder. Is there any way, at the start of each loop, to tell the application I want new empty questions object as opposed to referencing the existing ones? I know that you can in similar back end languguages so I refuse to beleive that something so simple doesn't exist in JavaScript too?
Declaring a variable for each array item is definitely missing.
QuestionsSetup: function(gameType) {
// Setup Resources
var c = this.View.children;
var player1qs = [];
var leftQ = 0;
var rightQ = 0;
var maxQValue = 50;
var minQValue = 1;
// Fill array with questions
for (var i = 0; i < 5; i++) {
var tempQuestion = {
qId: i,
leftQ: leftQ,
rightQ: rightQ,
correctAnswer: correctAnswer,
allAnswers: sortedAnswers,
questionText: questionText
}
// ...
//Add to array of questions
player1qs.push(tempQuestion);
}
}
Using a separate closure inside a loop also might be a good idea.
do this:
for (var i = 0; i < 5; i++) {
let questions = {};
// the rest....
you need to define the object first.
Maybe you should just initialize the questions object before initializing its properties, so the code should look like this:
//Place Questions into object
questions = {};
questions.qId = i;
questions.leftQ = leftQ;
questions.rightQ = rightQ;
questions.correctAnswer = correctAnswer;
questions.allAnswers = sortedAnswers;
questions.questionText = questionText;
//Add to array of questions
player1qs.push(questions);

How to get variable from different function [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 7 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
So what I'm trying to do is get a search term from one function getRandomVideo() and use it in a jQuery statement, so for example, get beethoven from the variable searches and use it as the search term to get back JSON information and append it to a div. I know next to nothing about jQuery so any help would be great thanks :)
<script type="text/javascript">
function getRandomVideo() {
var videos = [
'https://www.youtube.com/embed/kiTO7c_qeZs',
'https://www.youtube.com/embed/z4Hfv00eqoI',
'https://www.youtube.com/embed/7cdZYQB5ONE',
'https://www.youtube.com/embed/i1gE3nyQnKg',
];
var titles = [
'Beethoven - Music, Love and Wine',
'Mozart String Serenade No.13',
'Beethoven Sonata No. 31 in A Flat Major',
"Debussy - Children's Corner",
];
var images = [
"url('Assets/beethoven.jpg')",
"url('Assets/mozart.jpg')",
"url('Assets/beethoven.jpg')",
"url('Assets/debussy.jpg')",
]
var searches = [
'beethoven',
'mozart',
'beethoven',
'debussy',
]
var rand = Math.floor(Math.random()*videos.length);
var video = videos[rand];
var title = titles[rand];
var image = images[rand];
var search = searches[rand];
document.getElementById("songTitle").innerHTML = title;
document.getElementById("img").style.backgroundImage = image;
var htmlVideo = document.getElementById("randomVideo");
htmlVideo.src = video;
htmlVideo.onload=null;
return search
}
getRandomVideo();
$(document).ready(function(){
// Im not sure what to do here to get it to run when the page starts
// Get the value from our getRandomVideo()
var searchTerm = getRandomVideo();
var url = "http://api.trove.nla.gov.au/result?key=jja10ssv4950uh65&encoding=json&zone=newspaper&sortby=relevance&q=" + searchTerm + "&s=0&n=5&include=articletext,pdf&encoding=json&callback=?";
/*
* Perform the search using jQuery's getJSON method
* Requires the search URL
*/
console.log(url);
$.getJSON(url, function(data) {
$.each(data.response.zone[0].records.article, function(index, value) {
$("#output").append("<p>" + value.articleText +"</p>");
});
});
};
</script>
This should give you an idea as to how to accomplish this...
var getRandomVideo = (function(){
var _videos = [
'https://www.youtube.com/embed/kiTO7c_qeZs',
'https://www.youtube.com/embed/z4Hfv00eqoI',
'https://www.youtube.com/embed/7cdZYQB5ONE',
'https://www.youtube.com/embed/i1gE3nyQnKg',
];
var _titles = [
'Beethoven - Music, Love and Wine',
'Mozart String Serenade No.13',
'Beethoven Sonata No. 31 in A Flat Major',
"Debussy - Children's Corner",
];
var _images = [
"url('Assets/beethoven.jpg')",
"url('Assets/mozart.jpg')",
"url('Assets/beethoven.jpg')",
"url('Assets/debussy.jpg')",
];
var _searches = [
'beethoven',
'mozart',
'beethoven',
'debussy',
];
return {
videos: function(){ return _videos; },
titles: function(){ return _titles; },
images: function(){ return _images; },
searches: function(){ return _searches; }
};
})(); // this is the module pattern FYI
var rand = Math.floor(Math.random() * getRandomVideo.videos().length);
var video = getRandomVideo.videos()[rand];
var title = getRandomVideo.titles()[rand];
var image = getRandomVideo.images()[rand];
var search = getRandomVideo.searches()[rand];
document.getElementById("songTitle").innerHTML = title;
document.getElementById("img").style.backgroundImage = image;
var htmlVideo = document.getElementById("randomVideo");
In javascript, everything including variables are scoped by function so any variable declared inside a function such as...
function myFunction()
{
var a1 = "something";
}
var test = a1; // a1 would be undefined as it is out of scope of `myFunction()` so test would be too of course
By using the module pattern, you can expose properties/functions within the return{}; statement. NB: the underscores are just to identify private functions/objects etc ;)
Also if you were to do the below, you would be able to access a1 as it would cascade into global scope as it has not been declared...
function myFunction()
{
a1 = "something";
}
var test = a1; // a1 would be "something"
But I wouldn't suggest this... for a number of architectural reasons :-/

javascript push inside init method not updating array length correctly

I'm trying to create an array of objects with an init method, and when I push an object into an array, it should push another object into the array, while keeping track of the length of the array.. The problem is that it doesn't update the length of the array until all the objects have been added, so when each object tries to grab the length, they all get 0.
How can I have it update the length in this process?
here's the jfiddle: http://jsfiddle.net/bg3Vg/13/
As you can see it gives a message showing that the grouptotal is 5, but it seems as if the total counts up from the last pushed object to the first.. I need it to work in the correct order so that the last pushed object can retrieve the correct length.
var colorGroup = [];
var grouptotal = 0;
colorGroup.push(new groupdata(0) );
alert(grouptotal+","+colorGroup[colorGroup.length-1].parent);
function groupdata(parent) {
this.parent = parent;
this.refnum;
this.init = function()
{
grouptotal++;
this.refnum = colorGroup.length;
if(grouptotal<5)colorGroup.push(new groupdata( this.refnum ) );
}
this.init();
}
edit:
ok, I found a way to solve my problem I think. Let me know how horrid this solution is..http://jsfiddle.net/EqAqv/1/
var colorGroup = [];
var grouptotal = 0;
var colorGroupWait = [];
colorGroup.push(new groupdata(0) );
while(colorGroupWait.length>0){
var newcolorGroup = colorGroupWait.shift();
colorGroup.push(new groupdata(newcolorGroup) );
}
alert(grouptotal+","+colorGroup[colorGroup.length-1].parent);
alert(grouptotal+","+colorGroup[colorGroup.length-2].parent);
function groupdata(parent) {
this.parent = parent;
this.refnum;
this.init = function()
{
grouptotal++;
this.refnum = colorGroup.length;
if(colorGroup.length<5)colorGroupWait.unshift( this.refnum );
}
this.init();
}
JavaScript arrays do update the length property as soon as you push something on to them. The problem is that you're recursively calling the constructor, so the statement this.refnum = colorGroup.length is getting executed for each initialization BEFORE any push occurs.
In other words, JavaScript is working as expected.
Is there any particular reason you are doing it in this convoluted manner? It be more straightforward (and achieve the result you're looking for) if you just did it like this:
for(grouptotal=0; grouptotal<5; grouptotal++){
colorGroup.push( new groupdata(grouptotal) );
}
Also, it is convention in JavaScript to name object constructors with a capital letter. So, while groupdata is not invalid syntax, it is confusing: you should consider naming it Groupdata.
#EthanBrown has already pointed out the problems. Here is a solution that puts all the logic in the constructor, and avoids the problem of pushing the instance after having it created from a wrong number.
function GroupData(parentnum) {
this.parentnum = parentnum;
this.refnum = GroupData.colorGroup.length;
GroupData.colorGroup.push(this);
if (GroupData.colorGroup.length < 5)
new GroupData(this.refnum);
}
GroupData.colorGroup = [];
var root = new GroupData(0);
alert(GroupData.colorGroup.length+", "
+GroupData.colorGroup[GroupData.colorGroup.length-1].parentnum);

Javascript Functions Logic [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
wanted some help with a friend's code. We're working on something together, but I'm relatively new to JavaScript. I've included the code below and would like some help understanding the logic. I've understood it for the most part, but not getting the complete picture.
App.SummaryController = Ember.ObjectController.extend({
userExpense: function() {
var userExpenseMap = {}
var expenses = this.get('controllers.expenses');
expenses.forEach(function(expense){
if(userExpenseMap[expense.get('whoPaid')]){
userExpenseMap[expense.get('whoPaid')] += expense.get('amount');
}
else{
userExpenseMap[expense.get('whoPaid')] = expense.get('amount');
}
});
userExpenseList = []
for(var key in userExpenseMap){
var obj = {};
obj.name = key;
obj.expense = userExpenseMap[key];
userExpenseList.push(obj);
}
console.log(userExpenseList);
return userExpenseList;
}.property('controllers.expenses.#each.amount')
});
I'll explain the function, but if you are wanting the ember portion of it that opens a week long class.
userExpense: function() {
// create an object (hash)
var userExpenseMap = {}
// in ember, grab the expenses controller, this shouldn't work, because in order to
// access another controller he should have a needs: ['expenses'] in this controllers hash
var expenses = this.get('controllers.expenses');
//iterate over each expense, named expense in the iteration
expenses.forEach(function(expense){
// if the object hash contains the whoPaid already, increment it by this amount
if(userExpenseMap[expense.get('whoPaid')]){
userExpenseMap[expense.get('whoPaid')] += expense.get('amount');
}
// otherwise create a new person who paid (as the key and set the amount)
else{
userExpenseMap[expense.get('whoPaid')] = expense.get('amount');
}
});
// create a global list (bad practice)
userExpenseList = []
// iterate through all the property names (keys) in the object hash
for(var key in userExpenseMap){
// set obj to a new object/hash (obj is actually hoisted out of here
// so this isn't creating a new variable, just setting obj each time
var obj = {};
//set two properties on it, name and expense with the values from above
obj.name = key;
obj.expense = userExpenseMap[key];
// put it into the global list
userExpenseList.push(obj);
}
// print it out
console.log(userExpenseList);
// return it
return userExpenseList;
}.property('controllers.expenses.#each.amount')
and this is a computed property in ember, that's what the property function at the end is, and the portion on the inside is the dependency, so any time the amount on any instance of an expense which lives on the expenses controller (which is an array) changes the property will be marked as dirty (so if someone is observing it, or depends on it, they will update. The dependency updating etc is Ember Magic, not really Javascript related)

JavaScript stop referencing object after pass it to a function

I know JavaScript passes Objects by reference and thus I'm having a lot of trouble with the following code:
function doGradeAssignmentContent(dtos) {
var x = 5;
var allPages = [];
var stage = new App.UI.PopUpDisplay.PopUpStageAssignmentGrader(null, that);// pass launch element
for(var i = 0; i < dtos[0].result.students.length; ++i) {
var pagesSet = [];
for(var j = 0; j < dtos[0].result.questions.length; ++j) {
var questionObject = jQuery.extend(true, {}, new Object());
questionObject = dtos[0].result.questions[j];
if(dtos[0].result.students[i].answers[j].assignmentQuestionId === questionObject.questionId) {// expected, if not here something is wrong
questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;
questionObject.pointsReceived = dtos[0].result.students[i].answers[j].pointsReceived;
} else {
var theAnswer = findAssociatedStudentAnswer(questionObject.questionId, dtos[0].result.students[i].answers[j]);
if(theAnswer !== null) {
questionObject.answer = theAnswer.studentAnswer;
questionObject.pointsReceived = theAnswer.pointsReceived;
} else {
alert("Unexpected error. Please refresh and try again.");
}
}
pagesSet[pagesSet.length] = new App.UI.PopUpDisplay.StageAssignmentGradingPages[dtos[0].result.questions[j].questionType.charAt(0).toUpperCase() + dtos[0].result.questions[j].questionType.slice(1) + "QuestionAssignmentGradingPage"](j + 1, questionObject);
}
var studentInfo = {};
studentInfo.avatar = dtos[0].result.students[i].avatar;
studentInfo.displayName = dtos[0].result.students[i].displayName;
stage.addPageSet(pagesSet, studentInfo);
}
stage.launch();
}
First let me show you what the result (dtos) looks like so you can better understand how this function is parsing it:
The result (dtos) is an Object and looks something like:
dtos Array
dtos[0], static always here
dtos[0].result, static always here
dtos[0].questions Array
dtos[0].questions.index0 - indexN. This describes our Questions, each one is an Object
dtos[0].students Array
dtos[0].students[0]-[n].answers Array. Each student array/Object has an Answers array. Each student will have as many elements in this answers Array that there were questions in dtos[0].questions. Each element is an Object
Now what we do in this here is create this Object stage. Important things here are it has an array called "this.studentsPages". This array will ultimately have as many entries as there were students in dtos[0].students.
So we loop through this for loop disecting the dtos array and creating a pagesSet array. Here comes my problem. On the first iteration through the for loop I create this questionObject element. I also have tried just doing var questionObject = {}, but what you see now was just an attempt to fix the problem I was seeing, but it didn't work either.
So at the end of the first iteration of the outer for loop I call stage.addPageSet, this is what happens here:
var pageObject = [];
pageObject["questions"] = pageSet;
pageObject["displayName"] = studentInfo.displayName;
this.studentsPages[this.studentsPages.length] = pageObject;
if(this.studentsPages.length === 1) {// first time only
for(var i = 0; i < pageSet.length; ++i) {
this.addPage(pageSet[i]);
}
}
The important thing to take notice of here is where I add pageObject on to this.studentsPages which was an empty array before the first call. pageObject now has pageSet plus a little bit more information. Remember, pageSet was an Object and thus passed by reference.
On the next iteration of the for loop, when I hit this line:
questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;
It goes wrong. This changes the local copy of questionObject, BUT it also changes the copy of questionObjec that was passed to addPageSet and added to the studentsPages array in the first iteration. So, if I only had 2 students coming in, then when all is said and done, studentsPages hold 2 identical Objects. This should not be true.
The problem is questionObject in the doGradeAssignmentContent function is keeping a reference to the Object created on the previous iteration and then overrides it on all subsequent iterations.
What can I do to fix this?
Thanks for the help!
With out having looked at it too closely I believe you need to change the following:
// Before:
var questionObject = jQuery.extend(true, {}, new Object());
questionObject = dtos[0].result.questions[j];
// After:
var questionObject = jQuery.extend(true, {}, dtos[0].result.questions[j]);
I didn't look too closely if there are other instances in the code where this needs to be applied, but the core concept is to utilize jQuery's deep copy to generate a duplicate of the object you do not wish to retain a reference to.

Categories

Resources