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)
Related
I am programming a chat system. I always make a Localstorage variable when a new chat is opened. Created like this:
localStorage.setItem("chat_"+varemail, data);
Now i want to check how many of them I have so something like:
"chat_"+... count.
How can I do this?
You'd grab the array of keys of the localStorage object, and use Array.filter to grab only the items starting with "chat_":
var length = Object.keys(localStorage).filter(function(key) {
return /^chat_.+/.test(key);
}).length;
Here's a JSFiddle
Try something like this, loop through all items in localStorage and match against your pattern
function getChatCount(){
var chatCount = 0;
for(item in localStorage){
if(item.indexOf('chat_') > -1) chatCount++;
}
return chatCount;
}
Local storage is based on key, value pairs. AFAIK, you wouldn't be able to retrieve all values with a certain prefix.
One potential solution would be to store an object that contains these. Based on your needs you could store the objects in an array or object and then retrieve the entire set and find the count.
For example:
var chats = { count: 0 };
chats["chat_"+varemail] = data;
chats.count += 1;
localStorage.setItem('chats', data);
Then if you want a count, you would retrieve the object:
var chats = localStorage.getItem('chats');
//chats.count would give you the count.
Although, this would mean you have to manually maintain the count variable when adding or removing data. If you don't need the indexing ability, you could add the chats to an array and store that.
EDIT: It is possible to find properties with a certain prefix, as seen in an answer to this question.
I would offer to convert to localStorage.setItem("chat", JSON.stringify(stack)), where stack is an array of chat objects. This way, you have access to an array of chats which you can count, search within, etc.
Something like:
var chatStore =
{
Count: function () {
var stack = JSON.parse(localStorage.getItem("chats"));
if (!stack)
return 0;
return stack.length;
},
Peek: function () {
var stack = JSON.parse(localStorage.getItem("chats"));
if (!stack)
stack = [];
if (stack.length > 0)
return stack.pop();
},
Push: function (token) {
var stack = JSON.parse(localStorage.getItem("chats"));
if (!stack)
stack = [];
stack.push(token);
localStorage.setItem("chats", JSON.stringify(stack));
},
// more methods to you might wish to implement: search, insert, etc.
}
// usage:
chatStore.Push(chatObject); // sets the last chat
chatStore.Peek(); // gets the last chat
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);
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.
This is my first Q&A ever, so hopefully it's alright.
As someone who generally picks stuff up quickly, I found the information on this topic was sporadic and generally over complicated, with many people saying it simply couldn't be done. so here's it broken down very simply.
Take this scenario as an example, we have a number of form components (text boxes, buttons, etc.), all with a number of properties, all of which have values... and we want to store these in a javascript array.
Here's my tinkerings. This code doesn't explicitly answer a question, as no question was explicitly asked, however I hope you find it useful
For good measure, here also is a jsfiddle http://jsfiddle.net/cQ8Xc/
var $parent_arr = new Array();
var $child_arr = new Array();
//we can add the key => value pairs like so:
//(obviously they won't be done like this, more likely a loop for example)
//this works just fine $child_arr[$key] = $value;
$child_arr['Top'] = '12';
$child_arr['Left'] = '13';
$child_arr['Right'] = '14';
$child_arr['Bottom'] = '15';
//we can add the array to another array like so:
$parent_arr['component1'] = $child_arr;
//clear the array for reuse (note that it is obviously not nessecary to reuse the array)
$child_arr = [];
//refill it
//note that the child arrays don't have to be identical lengths or values
$child_arr['Height'] = '22';
$child_arr['Width'] = '23';
$child_arr['Colour'] = 'blue';
$parent_arr['component2'] = $child_arr;
//we can access the data like this:
alert($parent_arr['component1']['Top']);
alert($parent_arr['component2']['Colour']);
//these didn't work for me, you've likely seen them in other answers if you've been researching this topic
//alert(JSON.stringify($parent_arr['component1'], null, 4));
//alert(JSON.stringify($parent_arr['component1']));
//alert($parent_arr['component1'].join("\n"));
//the array can be looped over like so:
for(var component in $parent_arr) {
for(var propertyName in $parent_arr[component]) {
alert(component + '.' + propertyName + '=' + $parent_arr['component1'][propertyName]);
}
}
so I've been working on a project in Javascript that takes in objects the user provides and represents them in HTML. Right now they are represented in memory as an array, and in the display as a separate array. After integrating some code changes, problems have arisen in that the display array seems to be having troubles removing it's contents, thus things that should be removed don't disappear from the view.
Declaring lists:
this.divList = gDocument.getElementById( element );
this.objectList = [];
Adding an object to the lists:
addObject = function (address, type){
var newDiv = gDocument.createElement("div");
this.divList.appendChild( newDiv );
var d = this.createObject( newDiv, address, type );
if (undefined != d)
{
this.objectList.push(d);
}
}
The divList accurately reflects the objectList until any changes are made to the objectList at runtime. When restarted, the lists are in sync once again. When I tried to fix it, things were very complicated. I'm wondering if there is a better way to design such an idea (the object model and the graphical representation). Any comments would be helpful, thanks.
Question vagueness aside, my recommendation would be to store one list, not two, in memory. Each list element is an object with all the necessary data you need for that particular abstract "object" (the ones that "the user provides"). Something like this:
this.divList = gDocument.getElementById(element);
this.masterList = [];
var i,
len = this.divList.length;
for (i = 0; i<len; i++)
{
this.masterList.push({
elt: this.divList[i],
obj: /* however you'd create the object in this.objectList */
});
}
Edit: your addObject function would be changed to something like this:
addObject = function (address, type)
{
var newDiv = gDocument.createElement("div"),
newObj = {elt: newDiv,
obj: this.createObject(newDiv, address, type)};
this.masterList.push(newObj);
this.divList.appendChild(newDiv);
}
You should store a reference to the HTML element that you're appendChild()ing to. You're already doing this - but when you need to manipulate the individual elements (say, remove one), use the masterList instead:
removeObject = function (i)
{
var toRemove = this.masterList.splice(i, 1);
if (toRemove)
{
this.divList.removeChild(toRemove.elt);
}
}
See also Array.splice().