JS
I’ve explained what’s going on in the comments of the JS.
let people = [
{
title: "davisss1",
name: "Jeslyn Davis",
gender: "male",
age: 25,
profileDescription: "I recently moved from New York, I'm looking forward to meeting new people.",
status: "Single",
hasKids: "No",
wantsKids: "No",
religion: "Prefer not to say",
typeOfRelationship: "Long-term",
city: "Kansas City",
state: "Missouri",
favSport: "softball",
favDrink: "coke",
favIceCream: "cookies-n-cream",
favFood: "gelato",
favMusic: "pop",
imgs: "images/jeslyn.jpeg"
},
{
title: "chlogib",
name: "Chloe Gibbs",
gender: "female",
age: 24,
profileDescription: "I'm currently running my own bakery so if you're every in town and want to get a bite let me know. I also work part time ",
status: "Single",
hasKids: "No",
wantsKids: "Yes",
religion: "Nonreligious",
typeOfRelationship: "Long-term",
city: "Louisville",
state: "Kentucky",
favSport: "volleyball",
favDrink: "ice-tea",
favIceCream: "mango",
favFood: "cookies",
favMusic: "rock",
imgs: "images/chloe.jpeg"
}
];
// This is the HTML template which will be used for each person.
const PERSONTEMPLATE = `
<div class="imagebox">
<img src="[[IMAGE]]" image="images" />
<div class="text">
Title: [[TITLE]]<br>
Name: [[NAME]]<br>
Age: [[AGE]]<br>
Description: [[DESCRIPTION]]<br>
Status: [[STATUS]]<br>
Has kids: [[HASKIDS]]<br>
Want kids: [[WANTSKIDS]]<br>
Religion: [[RELIGION]]<br>
Type of relationship: [[LOOKINGFOR]]<br>
City:[[CITY]]<br>
State:[[STATE]]<br>
Favorite sport: [[FAVSPORT]]<br>
Favorite drink: [[FAVDRINK]]<br>
Favorite ice-cream flavor: [[FAVICECREAM]]<br>
Favorite food: [[FAVFOOD]]<br>
Favorite music: [[FAVMUSIC]]<br>
</div>
<button>[[BUTTONTEXT]]</button>
</div>`;
// Fired on-change
function checkGender() {
// Get the selected gender
let genderSelected = document.getElementById("gender").value;
// get the div to add the html to.
let peopleDiv = document.getElementById("people");
// Create a variable to which each appropriately gendered persons' HTML will be added to.
let htmlToBuild = '';
// Get the people by the selected gender using filter(), then use forEach to loop through each person in the returned array.
people
.filter(person => person.gender == genderSelected)
.forEach(function(person) {
// Gets the template and replaces the placeholder snippets.
// += appends to a string.
htmlToBuild += PERSONTEMPLATE
.replace('[[IMAGE]]',person.imgs)
.replace('[[TITLE]]',person.title)
.replace('[[NAME]]',person.name)
.replace('[[AGE]]',person.age)
.replace('[[DESCRIPTION]]',person.profileDescription)
.replace('[[STATUS]]',person.status)
.replace('[[HASKIDS]]',person.hasKids)
.replace('[[WANTSKIDS]]',person.wantsKids)
.replace('[[RELIGION]]',person.religion)
.replace('[[LOOKINGFOR]]',person.typeOfRelationship)
.replace('[[CITY]]',person.city)
.replace('[[STATE]]',person.state)
.replace('[[FAVSPORT]]',person.favSport)
.replace('[[FAVDRINK]]',person.favDrink)
.replace('[[FAVICECREAM]]',person.favIceCream)
.replace('[[FAVFOOD]]',person.favFood)
.replace('[[FAVMUSIC]]',person.favMusic)
.replace('[[BUTTONTEXT]]',person.name);
});
// Add the new HTML to the div.
peopleDiv.innerHTML = htmlToBuild;
}
The code here has a good separation of concerns and is readable. You can update your HTML template independently of replacing any values within it. There are no duplicate pieces of code (male + female for loops), just one array filter and one foreach.
Solution 2 :
I refactored some of the JavaScript code. Here’s the updated code.
The main problem with your approach here was that you were printing buttons inside a for loop inside the for loop. First loop prints out the main div that contains the information related to a specific person. The second loop, that was being used for printing button, was inside the first loop.
Furthermore, because the imagebox ID was repeated on the page, document.getElementById("imagebox") was selecting the first ID and was printing the buttons inside the first div.
Are you getting double the number of buttons that you should have with the above code?
if (genderSelected == "male") {
for (var i = 0; i < people.length; i++) {
if (people[i].gender == "male") {//Here you are checking to ensure you get only males
var content = `<div id="imagebox">` + `<img src="` + people[i].imgs + `" id="allimages"/>` + `<div id="text">` + `Title: ` + people[i].title + `<br>` + `Name: ` + people[i].name + `<br>` + `Age: ` + people[i].age + `<br>` + `Description: ` + people[i].profileDescription + `<br>` + `Status: ` + people[i].status + `<br>` + `Has kids: ` + people[i].hasKids + `<br>` + `Want kids: ` + people[i].wantsKids + `<br>` + `Religion: ` + people[i].religion + `<br>` + `Type of relationship: ` + people[i].typeOfRelationship + `<br>` + `City: ` + people[i].city + `<br>` + `State:` + people[i].state + `<br>` + `Favorite sport: ` + people[i].favSport + `<br>` + `Favorite drink: ` + people[i].favDrink + `<br>` + `Favorite ice-cream flavor: ` + people[i].favIceCream + `<br>` + `Favorite food: ` + people[i].favFood + `<br>` + `Favorite music: ` + people[i].favMusic + `<br>` + `</div>` + `</div>`;
allimages.innerHTML += content;
text.innerHTML += content;
function createButtons() {
for (var i = 0; i < people.length; i++) {//this creates a button for each person, regardless of gender
document.getElementById("imagebox").innerHTML += "<button>" + people[i] + "</button>";
}
}
createButtons(); //you are creating a button for each person here, regardless of gender(although you should be checking to see if the gender is correct)
}
Problem :
In my array of objects, each person has a set of information with an image. All of this information is inside of a div called imagebox. Now I want to add a button for each person in the array. Currently my code is creating multiple buttons instead of one per each object in my array. I attached an image to show what the page currently looks like. Like my image shows I have buttons outside the white div and also multiple. I just want one button inside of that white div per person, but I don’t understand what I’m doing wrong with my for loop.
var people = [
{
title: "davisss1",
name: "Jeslyn Davis",
gender: "male",
age: 25,
profileDescription: "I recently moved from New York, I'm looking forward to meeting new people.",
status: "Single",
hasKids: "No",
wantsKids: "No",
religion: "Prefer not to say",
typeOfRelationship: "Long-term",
city: "Kansas City",
state: "Missouri",
favSport: "softball",
favDrink: "coke",
favIceCream: "cookies-n-cream",
favFood: "gelato",
favMusic: "pop",
imgs: "images/jeslyn.jpeg"
},
{
title: "chlogib",
name: "Chloe Gibbs",
gender: "female",
age: 24,
profileDescription: "I'm currently running my own bakery so if you're every in town and want to get a bite let me know. I also work part time ",
status: "Single",
hasKids: "No",
wantsKids: "Yes",
religion: "Nonreligious",
typeOfRelationship: "Long-term",
city: "Louisville",
state: "Kentucky",
favSport: "volleyball",
favDrink: "ice-tea",
favIceCream: "mango",
favFood: "cookies",
favMusic: "rock",
imgs: "images/chloe.jpeg"
}
]
function checkGender() {
var genderSelected = document.getElementById("gender").value;
var allimages = document.getElementById("imagescontainer");
var text = document.getElementById("text");
allimages.innerHTML = "";
text.innerHTML = "";
if (genderSelected == "male") {
for (var i = 0; i < people.length; i++) {
if (people[i].gender == "male") {
var content = `<div id="imagebox">` + `<img src="` + people[i].imgs + `" id="allimages"/>` + `<div id="text">` + `Title: ` + people[i].title + `<br>` + `Name: ` + people[i].name + `<br>` + `Age: ` + people[i].age + `<br>` + `Description: ` + people[i].profileDescription + `<br>` + `Status: ` + people[i].status + `<br>` + `Has kids: ` + people[i].hasKids + `<br>` + `Want kids: ` + people[i].wantsKids + `<br>` + `Religion: ` + people[i].religion + `<br>` + `Type of relationship: ` + people[i].typeOfRelationship + `<br>` + `City: ` + people[i].city + `<br>` + `State:` + people[i].state + `<br>` + `Favorite sport: ` + people[i].favSport + `<br>` + `Favorite drink: ` + people[i].favDrink + `<br>` + `Favorite ice-cream flavor: ` + people[i].favIceCream + `<br>` + `Favorite food: ` + people[i].favFood + `<br>` + `Favorite music: ` + people[i].favMusic + `<br>` + `</div>` + `</div>`;
allimages.innerHTML += content;
text.innerHTML += content;
function createButtons() {
for (var i = 0; i < people.length; i++) {
document.getElementById("imagebox").innerHTML += "<button>" + people[i] + "</button>";
}
}
createButtons();
}
}
} else {
for (var i = 0; i < people.length; i++) {
if (people[i].gender == "female") {
var content = `<div id="imagebox">` + `<img src="` + people[i].imgs + `"id="allimages"/>` + `<div id="text">` + `Title: ` + people[i].title + `<br>` + `Name: ` + people[i].name + `<br>` + `Age: ` + people[i].age + `<br>` + `Description: ` + people[i].profileDescription + `<br>` + `Status: ` + people[i].status + `<br>` + `Has kids: ` + people[i].hasKids + `<br>` + `Want kids: ` + people[i].wantsKids + `<br>` + `Religion: ` + people[i].religion + `<br>` + `Type of relationship: ` + people[i].typeOfRelationship + `<br>` + `City: ` + people[i].city + `<br>` + `State:` + people[i].state + `<br>` + `Favorite sport: ` + people[i].favSport + `<br>` + `Favorite drink: ` + people[i].favDrink + `<br>` + `Favorite ice-cream flavor: ` + people[i].favIceCream + `<br>` + `Favorite food: ` + people[i].favFood + `<br>` + `Favorite music: ` + people[i].favMusic + `<br>` + `</div>` + `</div>`;
allimages.innerHTML += content;
text.innerHTML += content;
function createButtons() {
for (var i = 0; i < people.length; i++) {
document.getElementById("imagebox").innerHTML += "<button>" + people[i] + "</button>";
}
}
createButtons();
}
}
}
}
Comments
Comment posted by jsfiddle.net
Can you please share a working fiddle of the code?
Comment posted by placeholder.com
you can use a placeholder image
Comment posted by jsfiddle.net/heyitsme/b5ac1xph/4
@arximughal is the code visible? Here is the link:
Comment posted by Benjamin James Kippax
@charmy You don’t need them. You can apply your styling to each persons’ individual divs using the classes. The template replaces the ‘
‘ +REALLY+’
‘+’
‘ +HARD+’
‘+’
‘ +TO+’
‘ +’
‘+READ+’
‘+’
‘ +CODE+’
‘ in your for loop … means it’s more readable.
Comment posted by Benjamin James Kippax
@charmy No worries at all. Glad we got there in the end. There’s a concept called Template Literals, which is similar. But in general this is just refactoring re-used code and ensuring your code has a separation of concerns. A couple of helpful concepts to look-up: single responsibility principle, dry programming.
Comment posted by Benjamin James Kippax
@charmy in general, if you have code which is repeated and very similar. Like the same for loop but for different genders in this case, you should look to refactor that into it’s own function or if it’s a variable/object elevating its scope.
Comment posted by arximughal
I added the button label too. Right now it’s just the person’s name. You can change that too whatever you prefer.
Comment posted by Benjamin James Kippax
@charmy change your button selector from #imagebox to [id*=”imagebox”]
Comment posted by Benjamin James Kippax
@charmy in your CSS, you should have a selector for the buttons, right? That selector will probably have #imagebox button {yourcss} or something similar? Change it to [id*=”imagebox”] button {yourcss}
Comment posted by arximughal
Please check my answer, you’ll see that I create a separate ID for each person rendered based on the loop index (not the most efficient way, but it will give you an idea how to implement it) and then targeted the new ID to add the button inside the div.