So I have:
arrayofobj = [
{
property: "string", // "card" object with different data types
property2: integer
},
{
property: "string", // "card" object with different data types
property2: integer
},
{
//etc more cards
}
];
var playDeck = arrayofobj.slice(0);//creates copy of deck to "use" for game
shuffled(playDeck);//shuffles deck
playerHand = [];//empty array to save cards into
deal10(playDeck);//removes the 1st 10 out of playDeck and puts in playerHand
Now from the 10 that get drawn into playerHand, I'm trying to display them on screen. I have a field set up with:
<div id="playerHand"></div>
My attempt which hasn't been very successful:
for (var i = 0; i < playerHand.length; i++) {
content = playerHand[i];
x = document.getElementById('playerHand').appendChild(document.createElement('div'));
x.className = 'card' + [i];
document.getElementsByClassName('card' + [i]).textContent = content;
}
I haven't been able to achieve the desired effect. I'm a beginner as far as programming goes so I'm open to constructive criticism. So if you haven't gathered already what I'm trying to do is display each object or card on the screen as its own div (so that I can add click handlers to them and have the clicked one played on the screen... for example.)
I think the main problem is getElementsByClassName, which returns an array and not the actual reference to the element. See below:
var data, content, container, element;
container = document.getElementById('container');
data = [
{
name: "stringa"
},
{
name: "stringb"
}
];
for (var i = 0; i < data.length; i++) {
// Are you accessing an actual property in your code? It seems
// you are just referencing the whole object.
content = data[ i ].name;
// Just save the createElement reference ;)
element = document.createElement('div');
// Why are you appending [i] instead of i directly?
element.className = 'card' + i;
// By saving the element directly we don't have to query for
// the class in this step. The other problem was probably that
// `getElementsByClassName` returns an array, so you would have
// to call: vvv
// document.getElementsByClassName('card' + [i])[ 0 ]
element.textContent = content;
container.appendChild( element );
}
Obligatory JSFiddle: http://jsfiddle.net/tgtefsrm/1/
Related
How can I save DOM elements inside of a javaScript object? I want to update the page by updating the object.
Bellow I created and Added elements to the website using a for loop. I want to save some of those elements inside some objects properties so that I can update the html in the page by updating the textContent of the property value in the object.
for ( var i = 1 ; i <= numberOfPlayers ; i++ ){
//create object for each player.
var name = nameInputArray[i].value;
players["player" + i] = {
name: name,
score: 0,
fireStreak: 0,
xStreak: 0,
html: {}
}
//Create a Player box for each player.
var playerBox= document.createElement('div');
playerBox.classList.add('player_box');
document.getElementById('player-box-container').appendChild(playerBox);
var playerName = document.createElement('div');
playerName.textContent = players["player" + i].name;
playerName.classList.add('player_names');
playerBox.appendChild(playerName);
var playerScoreHeading = document.createElement('div');
playerScoreHeading.classList.add('player_score_heading');
playerScoreHeading.textContent = "Player Score:";
playerBox.appendChild(playerScoreHeading);
var playerScoreDiv = document.createElement('div');
playerScoreDiv.classList.add('player_score');
playerBox.appendChild(playerScoreDiv);
var playerScoreNumber = document.createElement('span');
playerScoreNumber.classList.add('player_score_number');
playerScoreNumber.textContent = players["player" + i].score;
playerScoreNumber.id = "player_score_number_" + i;
playerScoreDiv.appendChild(playerScoreNumber);
//THIS IS THE PART NOT WORKING!!!!!!!!!!!!!!!!!(THE NEXT LINE)
players["player" + i].html.score = document.getElementById("player_score_number_" + i);
playerScoreDiv.innerHTML += "pts";
}
for some reason when I try to access:
function changeScore(){
players.player1.html.score.textContent = 30;
}
It would change the inside the object but it will not render on the webpage.
Please help.
By reassigning an HTML string to playerScoreDiv.innerHTML, you lose all the element objects that you had previously created as descendants of playerScoreDiv: they are recreated (with obviously different object references) from the HTML.
So instead of:
playerScoreDiv.innerHTML += "pts";
do:
playerScoreDiv.appendChild(document.createTextNode('pts'));
So I have a dynamic variable that could be any integer from 5 to < 99 decided by the user.
var topLevelMenusTotalNum
Each top level menu has 5 fixed properties that I want to store which are mostly integers and some long numbers. And then recall for use in my bit of code.
Whats is the bext way for me to store these values in a storage system that can be dynamic in size?
I'm guessing I should store each top level menu as an object, with the 5 properties, i.e.
menu1.property1 = 500
menu1.property2 = 23
...
menu1.property5 = 24.3445345644
But how can I dynamically create the menu1, menu2, menu3 etc objects depending on how many the user has created?
Should I create the objects in an array? Or something else?
Does the order matter? If so, use an array.
Does the name matter? If so, use an object with named properties.
Do neither matter? Then it doesn't really make a difference. Arrays are slightly easier to loop over.
if you have an object, you can dynamically add items to it like so:
var menus = {
"menu1": {
//properties
},
"menu2": {
//properties
} //etc...
}
then you could add to it like so:
menus['menu' + newMenuNR] = {'property1': 21, 'property2': 10} //<-- properties in there
this is fully dynamic and won't result in problems later on, to loop through the object, you could use a 2-dimentional loop.
for(menu in menus) {
for(item in menu) {
alert(item.['property1']); //displays property of item in menu in menus (replace property with your own property names)
}
}
I will suggest you to use an object for top layer and each object will contain array as class member.
Object will help you to create dynamically based on user and each object of user will contain an array which has five properties.
I would suggest doing it with objects as long as the parameters can be named.
If you need a lot of objects, just keep an array of objects to search/sort/filter.
//Class (Hide this in some library script)
var Menu = (function () {
function Menu(parameters) {
if (parameters === void 0) { parameters = {}; }
this.node = document.createElement("ul");
this.items = [];
this.width = 100;
this.height = 100;
this.name = "";
this.title = "";
this.children = [];
//Apply parameters
for (var key in parameters) {
if (parameters.hasOwnProperty(key) && this.hasOwnProperty(key)) {
this[key] = parameters[key];
}
}
//Apply node parameter
this.node.title = this.title;
//Add to static
Menu._menus.push(this);
}
Menu.prototype.render = function () {
//Reset contents
this.node.innerHTML = "";
//Append sub-menues
for (var childIndex = 0; childIndex < this.children.length; childIndex++) {
var child = this.children[childIndex];
var li = document.createElement("li");
li.appendChild(child.render());
this.node.appendChild(li);
}
//Append generic items
for (var itemIndex = 0; itemIndex < this.items.length; itemIndex++) {
var item = this.items[itemIndex];
var li = document.createElement("li");
li.innerHTML = item;
this.node.appendChild(li);
}
//Return node
return this.node;
};
Menu._menus = [];
return Menu;
}());
//Implementation
//create menu
var topMenu = new Menu({ items: ["Just testing"], title: "Super!" });
//Add anonymous submenues
topMenu.children
.push(new Menu({ items: ["item 1"], title: "sub", name: "sub1" }), new Menu({ items: ["item 3", "item 2"], title: "sub", name: "sub2" }));
//Add to "bigList"
document.getElementById("bigList").appendChild(topMenu.render());
//Updates incoming
setTimeout(function () {
//Find menu with the most items + children (Which is easy with named parameters)
var m = Menu._menus
.filter(function (a) {
return a.title == "sub";
}).sort(function (a, b) {
return (b.items.length + b.children.length) - (a.items.length + a.children.length);
})[0];
//Add new item
m.items.push("Sweet right?");
//Update node
m.render();
}, 2000);
setTimeout(function () {
//Find last menu
var m = Menu._menus
.reverse()[0];
//Remove last item
m.items.splice(m.items.length - 1, 1);
//Update node
m.render();
}, 4000);
<div id="bigList">
Named parameters are lovely :-)
</div>
I'm looping through a js object with a nested for loop, stated below, it appends the first element correctly, but then throws the following error:
Can't set the property className of an undefined reference or empty reference. (not sure if exact error, translating from Dutch...)
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true}); //returns: [{"VideoName":"timelapse aethon2","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"},{"VideoName":"timelapse aethon3","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"}]
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
//alert(resultSet);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
videoElement.appendChild(document.createElement('div'));
videoElement.children[i].id='allVid' + i;
videoElement.children[i].className='col-md-4 col-xs-12';
//alert(typeof key)
var card = document.getElementById('allVid' + i);
alert(i);
card.appendChild(document.createElement('div'));
card.children[i].className='card card-block';
card.children[i].innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
}
}
}
}
[EDIT] added screenshot of how it looks
Your code has some significant logic issues. You're using nested loops, but appending to an element assuming that the outer loop counter will let you index into that element's children to get the element you just appended. Later, you try to get that same element again using getElementById. Then, you append a new element to your newly-created element, but try to access that new element using children[i] on the one you just created — at that point, the card element will only have a single child, so as of the second outer loop, it will fail.
createElement returns the element to you, so there's no reason at all to try to access it via children[i] (either time) or getElementById.
See comments:
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true});
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
// Create the card, give it its id and class
var card = document.createElement('div');
card.id='allVid' + i;
card.className='col-md-4 col-xs-12';
// Create the div to put in the card, give it its class and content
var div = document.createElement('div');
card.appendChild(div);
div.className='card card-block';
div.innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
// Append the card
videoElement.appendChild(card);
}
}
}
}
Side note: arrLenght looks like a typo (it should be th, not ht), but moreover, there's no reason to use a function to get the length of an array; it's available via the array's length property: parsedLength = parsed.length.
Side note 2: You may find these ways of looping through arrays useful.
Your problem is the if within the nested for:
if(obj.hasOwnProperty(key)) { ...
The variable i is increased even if the property is not "owned" (when the if condition returns false), so next time that the condition is true, i is out of bounds.
In my NodeJS app i get an JSON object within jade (which works fine). Here in i tried to collect(srcTweets) only the relevant data and return this in a new JSON object(stgTweets). Which i use for Dynamic Table use.
Here fore i use the following scrip:
var srcTweets = [];
var srcTweets = !{JSON.stringify(tweets)};
var aantalSrcTweets = srcTweets.length;
//Loop throug all tweets and collect all relevant elementen from srcTweet:
var stgTweet = {}
var stgTweets = [];
console.info('----------START LOOP--------------------');
for(var i = 0; i < aantalSrcTweets; i++){
console.info(i);
stgTweet.Id = srcTweets[i]._id;
stgTweet.userId = srcTweets[i].user.id;
stgTweet.userFollowerCount = srcTweets[i].user.followers_count;
stgTweet.userFriendCount = srcTweets[i].user.friends_count;
stgTweet.userFavouritesCount = srcTweets[i].user.favourites_count;
stgTweet.text = srcTweets[i].text;
stgTweet.coordinates = srcTweets[i].coordinates;
stgTweet.userLocation = srcTweets[i].user.location;
stgTweets[i] = stgTweet;
console.info(stgTweets[i]);
console.info(i);
}
console.info('----------END LOOP--------------------');
//here i get the same items
console.info(stgTweets[0]);
console.info(stgTweets[1]);
When i print different index numbers of the array "stgTweet[0] and stgTweet[1]" the same data is showed. I tried to figure it out by logging the elements in the for loop , but that looks fine. And i realy don't know where to look futher.
How do i fill the array with different objects in stead of the same object, what happens in the script above.
Here is an example of the srcTweets:
[
Object {
_id="56e19eb1ac5e621e0797c423",
truncated=false,
text="#Model_Symphony nu ja,
s... prima Energiequelle...",
more...
},
Object {
_id="56e1a73eac5e621e0797c424",
truncated=false,
text="Vandaag aangekondigd doo...",
more...
},
Object {
_id="56e1a7b4ac5e621e0797c425",
truncated=false,
text="Mooi bedrijfsbezoek aan ...",
more...
}
]
The reason is because you're reusing the same object for every element in the array and objects are assigned by reference in Javascript, so stgTweets[0] === stgTweets[1].
What you could do instead is move your stgTweet declaration inside the loop (or just re-assign the value directly as shown below) so that a new object is created for each array element:
var stgTweets = new Array(aantalSrcTweets);
for (var i = 0; i < aantalSrcTweets; i++){
stgTweets[i] = {
Id: srcTweets[i]._id,
userId: srcTweets[i].user.id,
userFollowerCount: srcTweets[i].user.followers_count,
userFriendCount: srcTweets[i].user.friends_count,
userFavouritesCount: srcTweets[i].user.favourites_count,
text: srcTweets[i].text,
coordinates: srcTweets[i].coordinates,
userLocation: srcTweets[i].user.location
};
}
i am trying to use jQuery.data() and save an Object to my HTML-Elements. Everytime i add an list-Element to my unordered List it only saves the last object to the specific li-Element. Every other li-Elements saved data gets thrown away!
I've built a little Example. JSBin-Example
On the left, i create a List with an Object saved to it. On the right i am trying to show the data related to the Object.
Why does it only show the Object related to the last HTML-Element?
Working example:
JSBin-Example
That's because you are modifying innerHTML property of the wrapper element. What happens is in each iteration the elements are regenerated, the current elements are removed and the new elements don't have any stored data. Using innerHTML property is the worst way of modifying element contents. You just need to create a li element and append it to the wrapper element:
var random = 0;
// var testObject = [];
function addNewItem(){
random += 1;
var id = "testId" + random;
var text = "This is my " + random + ". text";
var data = {id: id, text: text};
// testObject.push(data);
// You can pass an object as the second argument
// to jQuery constructor and it calls the
// corresponding methods as setter
$('<li></li>', {
text: text + JSON.stringify(data),
id: id,
data: data
}).appendTo('#listId');
}
// bind and trigger click event
$("#add").on('click', addNewItem).click();
I changed
for(var i = 0; i < testObject.length; i++){
var listItem = "";
var id = testObject[i].id;
listItem += liStart + id + liStart2;
listItem += testObject[i].text;
listItem += liEnd;
unorderedList.innerHTML += listItem;
$("#"+id).data(testObject[i]);
}
to this in your updatelist function
//for(var i = 0; i < testObject.length; i++){
var id = testObject[testObject.length-1].id;
listItems += liStart + id+"savedData" + liStart2;
listItems += JSON.stringify($("#"+id).data());
listItems += liEnd;
//}
savedData.innerHTML += listItems;
and it fixed the issue
To help you understand my comment on the question I thought it best I'd give an example of what I meant.
I didn't have enough time to fully go through the solution but wanted to give an example of what I'd call more readable code.
I've added all variables at the top of the function. This will allow you to read and find items much quicker if you needed to alter them.
I've also merged a lot of the string values that you had into an object, namely the li element.
I've never used $.data() as an object before so wasn't really aware how I could use it to set the values in the updateSavedData() $('li'), although the console.log() does show the correct key / values.
$(document).ready(function(){
var uID = 0;
var testObject = [];
var unorderedList = $("#listId");
var savedList = $("#savedData");
var TOL = 0; //TestObjectLength
var textTemplate = "This is my [0] text!";
function addNewItem(){
uID++;
testObject.push({id: uID, text: textTemplate.replace("[0]", uID)});
TOL = testObject.length-1;
updateList();
}
function updateList(){
var li = $('<li>', { id: testObject[TOL].id, data: testObject[TOL], text: testObject[TOL].text });
li.appendTo(unorderedList);
updateSavedData(li.data());
}
function updateSavedData(li){
console.log(JSON.stringify(li));
$('<li>', JSON.stringify(li)).appendTo(savedList);
}
addNewItem();
$("#add").on('click', addNewItem);
});
Working Example
http://jsbin.com/ralizazahe/1/edit?js,console,output
Anyone that wants to progress on that please do as I'd also like to see how this could be progressed more.
Update
Taken it a step more and refactored to this
$(document).ready(function(){
var $displayList = $("#listId");
var $savedList = $("#savedData");
var textTemplate = "This is my {0} text!";
var uID = 0; //Unique ID
var data = { id: null, text: null }; //Gives a reference
function init(){
uID++;
data = { id: uID, text: textTemplate.replace("{0}", uID) };
}
function addNewItem(){
init();
$('<li>', data).appendTo($displayList);
updateSavedData(data);
}
function updateSavedData(li){
$('<li>', li).appendTo($savedList);
}
addNewItem();
$("#add").on('click', addNewItem);
});
http://jsbin.com/bajekagoli/1/edit?js,console,output