First question ever, new to programming. I'll try to be as concise as possible.
What I want to do is to create a bunch of children inside a selected div and give each of them specific html content (from a predefined array) and a different id to each child.
I created this loop for the effect:
Game.showOptions = function() {
var i = 0;
Game.choiceElement.html("");
for (i=0; i<Game.event[Game.state].options.length; i++) {
Game.choiceElement.append(Game.event[Game.state].options[i].response);
Game.choiceElement.children()[i].attr("id","choice1");
}
};
Using the predefined values of an array:
Game.event[0] = { text: "Hello, welcome.",
options: [{response: "<a><p>1. Um, hello...</p></a>"},
{response: "<a><p>2. How are you?</p></a>"}]
};
This method does not seem to be working, because the loop stops running after only one iteration. I sincerely have no idea why. If there is a completely different way of getting what I need, I'm all ears.
If I define the id attribute of each individual p inside the array, it works, but I want to avoid that.
The idea is creating a fully functional algorithm for dialogue choices (text-based rpg style) that would work with a predefined array.
Thanks in advance.
The problem with your loop as I see it could be in a couple different places. Here are three things you should check for, and that I am assuming you have but just didn't show us...
Is Game defined as an object?
var Game = {};
Is event defined as an array?
Game.event = new Array();
Is Game.state returning a number, and the appropriate number at that? I imagine this would be a little more dynamic then I have written here, but hopefully you'll get the idea.
Game.state = 0;
Now assuming all of the above is working properly...
Use eq(i) instead of [i].
for (var i = 0; i<Game.event[Game.state].options.length; i++) {
Game.choiceElement.append(Game.event[Game.state].options[i].response);
Game.choiceElement.children().eq(i).attr("id","choice" + (i + 1));
}
Here is the JSFiddle.
Related
I have a JSON response from a server, which returns me a array with 32 objects (in this case). Something like this:
[{object1},{ object2},{ object3}, etc].
Each object have some info that I use to populate an html template. For that, I just use a simple loop:
for(var i = 0; i < api_empresaListar.length; i++)
{
var item = api_empresaListar[i];
var htmls;
htmls = $('...lots of html code');
...
Then it’s just a simple matter of finding/changing the values, and append items on the DOM. Everything works fine. BUT, for some next parts of the code, I would like to access all the info from the object I used to build the html elements (I just show part of the info). So, after searching a lot, I tried to use data, like this:
var tp = htmls.find(".rl_grupo"); // the main div of each html element created in the loop
$(tp).data('key', api_empresaListar[i]); // here, I expected to just insert the object data in each created item.
But when I try it in the console, I got the object info as expected, but always from the last element in the array. Why is that happening? I believe it might be something stupid, but I can’t figure it out.
So, any ideas on how to solve this, or another method to make this work is appreciated. I made it work by setting some "display:none" placeholder html tags and populate those with the info I need later, but looks like a poor solution...
You should not set your htmls variable in the loop. I think that you crush its content every turn, that's why you only have the last item. You should do something like this:
var htmls = $('<div></div>');
for(var i = 0; i < api_empresaListar.length; i++) {
htmls.append($('...lots of html code'));
}
How about setting an index number on each element inside of your html creating code, then iterating over the $('.rl_grupo') elements, like this?
$('.rl_grupo').each(function(){
var index = $(this).data('index');
var currentData = api_empresaListar[index];
$(this).data('key', currentData);
})
Knowledge: First week Javascript
I am trying to learn real javascript and avoid jquery at all cost. Now I am I recently learned that id's can be style easily but not classes. In order to style a class I need to loop through the dom for the class. My original code works, however my new one does not. Best practices aside for a moment, I am trying to learn how this works regardless if it is a perfect solution or not.
Problem specifics: In my new code I stored the two get functions in keys within an associative array. So I have objects which I would like my for loop to understand. I am trying to make it work like my first code.
What I tried: Honestly, I read something about squared bracket notation and how it can be useful. I felt a bit overwhelmed to be honest. What I tried was:
source[_class][i]
Maybe _class is undefined even though I defined it. I specified what class contains. Honestly im lost and would appreciate some help and of course I welcome best practice advice as well.
I want to be a better programmer and I would appreciate some insight. I dont want to start with jquery.
My experiment:
setTimeout(function() {
var source = {_id: document.getElementById('box'),
_class: document.getElementsByClassName('hint')};
for (var i = 0; i < source[_class].length; i++) {
source[_class + i].style.opacity = '0';
console.log(i);
}
}, 1000);
My original working code:
// setTimeout(function() {
// var divs = document.getElementsByClassName('hint');
// for (var i = 0; i < divs.length; i++) {
// divs[i].style.opacity = '0';
// console.log(i);
// }
// }, 1000);
Use source._class.length instead of source[_class].length and source._class[i] instead of source[_class + i]:
for (var i = 0; i < source._class.length; i++) {
source._class[i].style.opacity = '0';
console.log(i);
}
source is an object and has a property _class. You can access properties either as source._class or as source['_class'].
The property source._class is an collection of DOM nodes itself so it can be accessed like an array. You can access array elements like this: array[index].
So you have both an object with properties and an array with elements. You need to access their contents appropriately.
Styling should be done with css, not loops, because using css is an order of magnitude faster.
Create css class definitions for your set of styles and then simply change the name of the class on your elements to change their style.
Also, look into using css selectors to query the DOM. This is done with querySelector for a single element, or querySelectorAll for a set of elements. Note that jQuery wraps this functionality and that is where the name is derived.
For your specific example, the problem was with accessing the array, instead of adding the i index, you need to reference the array, and you also need to make sure you are using a string index or a dot notation (such as source._class) in order to reference that object's property
for (var i = 0; i < source['_class'].length; i++) {
source['_class'][i].style.opacity = '0';
console.log(i);
}
You missed a square bracket and it's text not a variable:
source[_class + i].style.opacity = '0';
should be
source["_class"][i].style.opacity = '0';
This question already has answers here:
Why do multiple `.appendTo` calls on a newly created jQuery element only append it once?
(2 answers)
Closed 3 months ago.
I tried looking for an answer here but all of the questions related to my issue are a bit too complicated for someone who just started learning JavaScript like me.
I want to create a grid of divs with js/jquery based on user input (eg: if user chooses width = 16, then he will see a 16x16 grid).
Now, I figured, I'll add a DOM element with var $smallDiv = $('<div class="smallDiv"></div>');
And here is the loop that adds the needed number of divs based on user input:
function addDiv() {
$('#container').append($smallDiv);
}
for (i = 1; i <= divCounter * divCounter; i++){
addDiv();
}
The problem is that this will always create only one div. The loop runs the required number of times, I've checked this using console.log(). So it clearly works, but I get the feeling that each time it loops, the new div overwrites the previous. That wasn't my expectation of .append().
I've managed to get around the problem by making the $smallDiv variable a normal one (removing $ from its value, making it just text) but I would love to know how are these two variables different and why does one work in the above scenario but the other does not.
And make it easy on me, I just started learning JS/jQuery.
In the loop, you are appending the same dom element reference($smallDiv) multiple times, which means the element will be added only once.
Instead in each iteration of the loop, you need to create new instance - you can use .clone() to do that.
function addDiv() {
$('#container').append($smallDiv.clone());
}
As an alternative to Arun P Johny solution, this seems to work as well:
var smallDiv = '<div class="smallDiv"></div>'
function addDiv() {
$('#container').append(smallDiv);
}
for (i = 1; i <= divCounter * divCounter; i++){
addDiv();
}
This way its not the same dom element but instead we use a simple string for append.
Attempting to build a resume creator as a project for codeacademy.
I'm using a button to "save" the user's input to an array so it can later be appended into the resume.
However, I'm failing at getting the data to "save" to the array. I've looked at similar questions here on stackoverflow and I cannot for the life of me figure out what I am doing wrong.
here's my fiddle
specific code block I'm having trouble with:
$('#experiencesave').click(function(){
for (var i = 0; i < jobs; i++){
jobtitle.push = $('#jobtitle'+i).val();
}
$('#morejobs').append(jobtitle);
});
Well, .push [MDN] is a function which has to be called:
jobtitle.push($('#jobtitle'+i).val());
As an alternative solution, instead of using a for loop, you might want to use .map to collect the values:
var jobtitle = $('input[id^=jobtitle]').map(function() {
return this.value;
}).get();
I don't see a reason to give each of those input elements an ID though. Just give them a class. That makes it a bit easier to bulk-process them later. E.g. the selector could then just be $('input.jobtitle').
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript infamous Loop problem?
I am having a small issue, and it would be very nice if some of you could realize about what kind of logic is missing here, since I cannot seem to find it:
I have an array with the results of some previous operation. Let's say that the array is:
var results = [0, 1];
And then I have a bunch of code where I create some buttons, and inside a for loop I assign a different function to those buttons, depending on the position of the array. The problem is that for some reason, all the buttons created (two in this case) come out with the function assigned to the last value of the array (in this case, both would come out as one, instead of the first with 0 and the second with 1)
This is the code:
for (var i = 0; i < results.length; i++) {
var br2 = b.document.createElement("br");
var reslabel = b.document.createTextNode(Nom[results[i]].toString());
var card = document.createElement("input");
card.type = "button";
id = results[i]; // this is the problematic value.
card.onclick = newcard; // this function will use the above value.
card.value = "Show card";
divcontainer.appendChild(br2);
divcontainer.appendChild(reslabel);
divcontainer.appendChild(card);
}
As it is, this code produces as many buttons as elements in the array, each with its proper label (it retrieves labels from another array). Everything is totally fine. Then, I click the button. All the buttons should run the newcard function. That function needs the id variable, so in this case it should be:
First button: runs newcard using variable id with value 0
Second button: runs newcard using variable id with value 1
But both buttons run using id as 1... why is that?
It might be very simple, or maybe is just that in my timezone is pretty late already :-) Anyways, I would appreciate any comment. I am learning a lot around here...
Thanks!
Edit to add the definition of newcard:
function newcard() {
id = id;
var toerase = window.document.getElementById("oldcard");
toerase.innerHTML = "";
generate();
}
the function generate will generate some content using id. Nothing wrong with it, it generates the content fine, is just that id is always set to the last item in the array.
Your id is a global variable, and when the loop ends it is set to the last value on the array. When the event handler code runs and asks for the value of id, it will get that last value.
You need to create a closure to capture the current results[i] and pass it along (this is a very common pitfal, see Javascript infamous Loop problem?). Since newcard is very simple, and id is actually used in generate, you could modify generate to take the id as a parameter. Then you won't need newcard anymore, you can do this instead:
card.onclick = (function(id) {
return function() {
window.document.getElementById("oldcard").innerHTML = "";
generate(id);
};
}(results[i]));
What this does is define and immediately invoke a function that is passed the current results[i]. It returns another function, which will be your actual onclick handler. That function has access to the id parameter of the outer function (that's called a closure). On each iteration of the loop, a new closure will be created, trapping each separate id for its own use.
Before going on, a HUGE thank you to bfavaretto for explaining some scoping subtelties that totally escaped me. It seems that in addition to the problems you had, you were also suffering from scoping, which bit me while I was trying to craft an answer.
Anyway, here's an example that works. I'm using forEach, which may not be supported on some browsers. However it does get around some of the scoping nastiness that was giving you grief:
<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
var card = document.createElement("input");
card.type = "button";
card.onclick = function() {
newcard( result );
}
card.value = "Show card";
document.body.appendChild(card);
});
function newcard(x) {
alert(x);
}
</script>
</body>
</html>
If you decide to stick with a traditional loop, please see bfavaretto's answer.