So I'm trying to create an online shop using HTML and Javascript as an exercise. I'm currently working on a dropdown menu which allows me to select the category of the item I wish to shop for (etc. electronics, clothes) but I'm having trouble getting all these values related to the category to show up.
So for example, I have a part of a javascript file below. The line div.innerHTML = (electronics.store) lets me print out the electronics store name "Mike's Computers" to the HTML file on my browser but I'm not quite sure how to access all the objects under its inventory. Is there a way to possibly iterate through the whole electronics inventory and print out each of the items and its cost/information below it and such?
If not, how would I go about printing things like the laptop brand name? Would it just be div.innerHTML = (electronics.inventory[0].brand) to print out the word "iMac"? I'm very confused and would appreciate any help possible.
Ultimately, I'd want my information to show up on the HTML page like:
Mike's Computers
Laptops
iMac $2000
Dell $600
Computers
Windows PC $1300
and so on.
function showOptions(){
let userPicked = document.getElementById("list").value;
var div = document.getElementById("div");
if(userPicked == 'one'){
div.innerHTML = (electronics.store);
}else{
alert("You must select a store.");
}
}
let electronics = {
store: "Mike's Computers",
inventory: {
"Laptops": {
0: {
brand: "iMac",
cost: 2000
},
1: {
brand: "Dell",
cost: 600
}
},
"Computers": {
2: {
brand: "Windows PC",
cost: 1300
}
}
}
};
Step one, take as much presentation out of your JavaScript as possible. Create the structure using HTML. Then populate that structure using JavaScript. That way if you want to change the layout, you're changing HTML and CSS and NOT Javascript. Use the <template> tag to create the structure of the repeating items.
Step Two, iterate the properties, cloning our template, then add to the DOM.
//Get the template
var template = document.getElementById("inventoryItem");
function showOptions() {
/*let userPicked = document.getElementById("list").value;
var div = document.getElementById("div");
if(userPicked == 'one'){
div.innerHTML = (electronics.store);
}else{
alert("You must select a store.");
}*/
document.querySelector("#store .storeName").innerHTML = electronics.store;
generateInventory(document.querySelector("#store .laptops > ul"), electronics.inventory.Laptops);
generateInventory(document.querySelector("#store .computers >ul"), electronics.inventory.Computers);
}
function generateInventory(node, object) {
//Iterate the properties
for (var itemName in object) {
if (Object.prototype.hasOwnProperty.call(object, itemName)) {
let item = object[itemName];
//Clone the template
let clone = template.content.cloneNode(true);
//Populate the content
clone.querySelector(".brand").textContent = item.brand;
clone.querySelector(".cost").textContent = clone.querySelector(".cost").textContent + item.cost;
//Append to the DOM
node.appendChild(clone);
}
}
}
let electronics = {
store: "Mike's Computers",
inventory: {
"Laptops": {
0: {
brand: "iMac",
cost: 2000
},
1: {
brand: "Dell",
cost: 600
}
},
"Computers": {
2: {
brand: "Windows PC",
cost: 1300
}
}
}
};
showOptions();
#store ul {
list-style: none;
padding-left: 0;
}
#store ul ul {
padding-left: 1em;
}
<div id="store">
<h1 class="storeName"></h1>
<ul class="inventory">
<li class="laptops">
<h2>Laptops</h2>
<ul></ul>
</li>
<li class="computers">
<h2>Computers</h2>
<ul></ul>
</li>
</ul>
</div>
<template id="inventoryItem">
<li>
<div class="brand"></div>
<div class="cost">$</div>
</li>
</template>
The code for duplicating the template is modified from: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
Here is sample code to add the data.
let electronics = {
store: "Mike's Computers",
inventory: {
"Laptops": {
0: {
brand: "iMac",
cost: 2000
},
1: {
brand: "Dell",
cost: 600
}
},
"Computers": {
2: {
brand: "Windows PC",
cost: 1300
}
}
}
};
function showOptions(){
let userPicked = document.getElementById("list").value;
var div = document.getElementById("div");
if(userPicked == 'one'){
var newContent = (electronics.store);
newContent += '<br>';
Object.keys(electronics.inventory).forEach(key => {
newContent += '<br>';
newContent += key;
newContent += '<br>';
var items = Object.values(electronics.inventory[key]);
items.forEach(item => {
newContent += ` ${item.brand} $${item.cost}`;
newContent += '<br>';
});
});
div.innerHTML = newContent;
}else{
alert("You must select a store.");
}
}
showOptions();
<input type="text" id="list" value="one">
<div id="div"> </div>
You can iterate through the electronics store inventory with a for loop like so
for (let [key, value] of Object.entries(electronics))
Then in the body of the for loop, you can call the key and value and append it to the innerHTML like you are already doing above.
Related
I'm trying to add a bootstrap card inside a div called [itemscontainer] using javascript
by document.getElementById("itemscontainer").innerHTML so i want the cards to be inserted inside the itemscontainer only one time like this :-
but the problem is the items cards keeps reapet them salves more than one time like:-
what i want is to clear the itemscontainer first before adding the cards and this is what i have tried so that the items will be only one cards for each item
// clear function
function clear(){
document.getElementById("ssst").innerHTML = ""
}
// listener append all items to the inventory
window.addEventListener('message', (event) => {
let data = event.data
if(data.action == 'insertItem') {
let name = data.items.name
let count = data.items.count
let icon = data.items.icon
if(document.getElementById("ssst").innerHTML == ""){
clear()
}else{
document.getElementById("ssst").innerHTML +=
"<div class='card holder'>"+
'<div class="card-body">'+
'<img src="icons\\'+icon+'" style="position:absolute;left:15%;width:40px; height:36px;" alt="">'+
'<h4 id="counter">'+count+'</h4>'+
'</div>'+
'<span class="itemname">'+name+'</span>'+
'</div>";'
}
}
})
The real solution is to figure out why you are getting the items more than once. With the information you provided that is impossible for me to answer. So the only thing we can recommend is how to prevent items from being added more than once.
If your messaging system returns duplicates you can determine if you have seen it. If you do, replace it. Otherwise add it.
window.addEventListener('message', (event) => {
const data = event.data;
console.log(data)
if (data.action == 'insertItem') {
let name = data.items.name
let count = data.items.count
let icon = data.items.icon
const html = `
<div class='card holder' data-name="${name}">
<div class="card-body">
<img src="icons/${icon}" style="position:absolute;left:15%;width:40px; height:36px;" alt="${icon}">
<h4 id="counter">${count}</h4>
</div>
<span class="itemname">${name}</span>
</div>`;
const elemExists = document.querySelector(`[data-name="${name}"]`);
if (elemExists) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
elemExists.replaceWith(doc.body);
} else {
document.getElementById("ssst").insertAdjacentHTML("beforeend", html);
}
}
});
window.postMessage({
action: 'insertItem',
items: {
name: 'foo',
count: 1,
icon: 'foo'
}
});
window.postMessage({
action: 'insertItem',
items: {
name: 'bar',
count: 40,
icon: 'barrrrrr'
}
});
window.postMessage({
action: 'insertItem',
items: {
name: 'foo',
count: 1000,
icon: 'foo'
}
});
<div id="ssst"></div>
Why are you using the if statement, what are you checking for?
remove the if statement, I can't see the reason for it to be used here.
clear()
and the rest of your code.
I'm having a bit of trouble with this problem. I'm working on the project of an e-commerce application that works on several html pages. I managed to push products through the cart html page, but I can't seem to find a way to update on this page only the quantity of a product and not push every elements of said product (images, id, etc). Onclick, if product exists, I only want quantity to be updated. Here's the code if any of you can help me out that'd be greatly appreciated.
setItems(kanap);
function setItems(kanap) {
let cart = JSON.parse(localStorage.getItem('cart'));
let imgKanap = kanap.imageUrl;
let idKanap = kanap._id;
let colorKanap = colors.value;
let quantityKanap = parseInt(quantity.value);
let key = idKanap + ' ' + colorKanap;
let cartItem = {
id: idKanap,
color: colorKanap,
quantity: quantityKanap,
kanap: kanap
};
if (cart === null) {
cart = [];
}
cart.push(cartItem);
localStorage.setItem('cart', JSON.stringify(cart));
function addProduct(cartItem) {
var found = false;
for (key in cartItem) {
if (cartItem[key].idKanap == idKanap) {
cartItem[key].quantityKanap += quantityKanap;
found = true;
break;
}
}
if (!found) {
cart.push(cartItem);
}
}
addProduct();
}
<div class="item__content__addButton">
<button id="addToCart" type="submit">Ajouter au panier</button>
</div>
<section class="cart">
<!-- <section id="cart__items">
<article class="cart__item" data-id="{product-ID}">
<div class="cart__item__img">
<img id ="image" alt="Photographie dun canapé">
</div>
<div class="cart__item__content">
<div class="cart__item__content__titlePrice">
<h2 class=title></h2>
<p class =price></p>
</div>
<div class="cart__item__content__settings">
<div class="cart__item__content__settings__quantity">
<p class= quantity>Qté : </p>
<input type="number" class="itemQuantity" name="itemQuantity" min="1" max="100" value="">
</div>
<div class="cart__item__content__settings__delete">
<p class="deleteItem">Supprimer</p>
</div>
</div>
</div>
</article> -->
</section>
There's a few approaches you can take, but I am using .find to look through your cart.
If the .find() function finds an item with the same id as you're about to add, it will up the quantity of the existing item instead of appending another object with the same ID.
I used a mock local storage since local storage doesn't work in these snippets so just ignore that and use what you've been doing for local storage access.
let mockLS = null;
// guessed at the structure here, you may have something slightly different
const exampleItem = {
_id: "abc",
imageUrl: "imageurlexample",
colors: {
value: "red"
},
quantity: {
value: 1
}
}
const exampleItem2 = {
_id: "abc2",
imageUrl: "imageurlexample2",
colors: {
value: "blue"
},
quantity: {
value: 1
}
}
function setItems(kanap) {
//let cart = JSON.parse(localStorage.getItem('cart'));
// using a mock localstorage here since it doesn't work within this snippet, use what you currently have instead
let cart = mockLS;
let imgKanap = kanap.imageUrl;
let idKanap = kanap._id;
let colorKanap = kanap.colors.value;
let quantityKanap = parseInt(kanap.quantity.value);
let key = idKanap + ' ' + colorKanap;
let cartItem = {
id: idKanap,
color: colorKanap,
quantity: quantityKanap
//kanap: kanap not sure why you want the whole obj here so I left this one out
};
if (cart === null) {
cart = [];
}
// here is the case where cart exists and there may be the same item in it
const itemExists = cart.find(item => {
if(item.id === idKanap) {
item.quantity += quantityKanap;
return true;
}
return false;
})
if (!itemExists) {
cart.push(cartItem);
}
//localStorage.setItem('cart', JSON.stringify(cart));
mockLS = cart;
}
setItems(exampleItem);
setItems(exampleItem2);
setItems(exampleItem);
console.log(mockLS)
I am trying to add a class when looping through an array, here is my current code:
var users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
];
var div = "<div>";
for (var i = 0; i < users.length; i++) {
div += "<p>" + users[i].name + "</p>";
div += "<p>" + users[i].id + "</p>";
div += "<p>" + users[i].number + "</p>";
}
div += "</div>";
document.getElementById("usersList").innerHTML = div;
<div class="contact-container">
<div class="navbar">
<ul>
<li>
<img src="https://img.icons8.com/ios-filled/50/000000/contact-card.png" />
</li>
<li>
View
</li>
<li>
Add
</li>
...
</ul>
</div>
<div class="users" id="usersList">
</div>
Is there any way I can add a class when looping?
Why don't you put a class right there while looping?
like this
for (var i = 0; i < users.length; i++) {
div += "<p class='myclass'>" + users[i].name + "</p>";
div += "<p class='myclass'>" + users[i].id + "</p>";
div += "<p class='myclass'>" + users[i].number + "</p>";
}
Just add it into your HTML
for (var i = 0; i < users.length; i++) {
div += "<p class='user-name'>" + users[i].name + "</p>";
div += "<p class='user-id'>" + users[i].id + "</p>";
div += "<p class='user-number'>" + users[i].number + "</p>";
}
var users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
];
var div = "<div>";
for (var i = 0; i < users.length; i++) {
div += "<p class='user-name'>" + users[i].name + "</p>";
div += "<p class='user-id'>" + users[i].id + "</p>";
div += "<p class='user-number'>" + users[i].number + "</p>";
}
div += "</div>";
document.getElementById("usersList").innerHTML = div;
.user-name {
color: red;
}
.user-id {
color: blue;
}
.user-number {
color: green;
}
<div class="contact-container">
<div class="navbar">
<ul>
<li>
<img src="https://img.icons8.com/ios-filled/50/000000/contact-card.png" />
</li>
<li>
View
</li>
<li>
Add
</li>
...
</ul>
</div>
<div class="users" id="usersList">
</div>
You could try creating your elements like this:
let div = document.createElement("div");
let p = document.createElement("p");
then add the class name:
p.className = "css class";
then add the parts to their parents:
div.appendChild(p);
document.getElementById("usersList").appendChild(div);
This is cleaner and more efficient than adding elements with innerHTML
While you've already accepted an answer, I thought this might be an interesting opportunity to try to learn – for my own benefit, but hopefully to contribute an answer – about using custom elements.
So, with that in mind see the code below with its explanatory comments (though this remains something of a black-magic to me, hence my interest in working on it to formulate an answer):
// defining the custom-element, naming it 'user-card' which
// will lead to the element being a <user-card> element in the DOM:
customElements.define('user-card',
class extends HTMLElement {
constructor() {
super();
// we get the <template> element via its id (other
// selection methods are available, of course):
let template = document.getElementById('user-card');
// and retrieve its content:
let templateContent = template.content;
// here we assign its shadow root as 'open', which
// allows us - and JavaScript - to modify it:
const shadowRoot = this.attachShadow({
mode: 'open'
})
// and here we append the content of the <template>,
// including its child nodes (the 'true' argument
// to cloneNode()):
.appendChild(templateContent.cloneNode(true));
}
}
);
// your data:
let users = [{
name: "Jan",
id: "1",
number: "111-111-111"
},
{
name: "Juan",
id: "2",
number: "222-222-222"
},
{
name: "Margie",
id: "3",
number: "333-333-333"
},
{
name: "Sara",
id: "4",
number: "444-444-444"
},
{
name: "Tyrell",
id: "5",
number: "555-555-555"
},
],
userDiv = document.querySelector('#usersList');
// here we use Array.prototype.forEach() to iterate over the
// data, along with an anonymous Arrow function to pass the
// current user Object into the body of the function:
users.forEach(
(user) => {
// we create a new <user-card> element:
let card = document.createElement('user-card'),
// we create a new <li> element:
li = document.createElement('li'),
// we create a document fragment to contain the
// HTML we're going to create to hopefully minimise
// repaints:
fragment = document.createDocumentFragment();
// we then use Object.prototype.keys() to iterate over the
// array of Object keys returned (in order to access the
// contents of the user Object), and pass that key into
// the body of the function:
Object.keys(user).forEach(
(key) => {
// we create a clone of the <li> element:
let clone = li.cloneNode();
// we apply the class-name of the current key, so
// each element gets a class of 'name', 'id' or 'number',
// obviously other classes could be used but these made
// the most sense given the context:
clone.classList.add(key);
// because the <style> of the <user-card> element's template
// doesn't (seem to) apply to content added later, we use
// CSSStlyleDeclaration.setProperty() to set the relevant
// CSS properties of the cloned <li> element; here we
// define the 'grid-area' property to properly place the
// current element into the appropriate grid-area (defined
// in the <template>):
clone.style.setProperty('grid-area', key);
// we add the property-value of the current Object key:
clone.textContent = user[key];
// and append the clone to the fragment, using
// Element.append():
fragment.append(clone);
})
// once all the data is within the document fragment, we
// append that fragment to the <user-card> element:
card.append(fragment);
// and then append that <user-card> to the relevant ancestor
// <div> in the document:
userDiv.append(card);
});
/* a very basic reset, to minimise cross-browser differences and
and reset elements to their basic 'zero-style' state: */
*,
::before,
::after {
box-sizing: border-box;
font-size: 1rem;
font-family: Calibri, Helvetica, Ubuntu, Arial, sans-serif;
line-height: 1.4;
margin: 0;
padding: 0;
}
.users {
/* specifying display: grid, since it's a typical (and
relatively aesthetic) convention for 'cards': */
display: grid;
gap: 0.5em;
/* allows the grid to adjust its layout to best fit the
content within the constraints of the device: */
grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
margin: 1em auto;
max-width: 90vw;
}
<!-- the template element that contains the structure to be re-used, with an id
attribute for easy access via JavaScript, though other means of selection
are possible -->
<template id="user-card">
<!-- because the defined style of the light DOM (or COM) doesn't penetrate
into the shadow root we declare relevant CSS here, though there are
concerns about this too; from experimentation the CSS declared here
will target elements present in the <template> but not content added
later, via JavaScript: -->
<style>
ol {
border: 1px solid #ccc;
list-style-type: none;
display: grid;
gap: 0.5em;
grid-template-areas:
"id name name"
"number number number";
padding: 0.25em;
margin: 0;
}
</style>
<!-- I've chosen to use an <ol> since the data seems to be
ordered/structured: -->
<ol>
<!-- we use a <slot> element to contain the data we'll be appending
(later) via JavaScript: -->
<slot></slot>
</ol>
</template>
<!-- for reasons of brevity I removed the extraneous content and retained
only the minimal content relevant to the demo, which is why we have
only the elements below: -->
<div class="contact-container">
<div class="users" id="usersList"></div>
</div>
JS Fiddle demo.
References:
HTML:
<slot>.
<template>.
JavaScript:
Arrow functions.
Array.prototype.forEach().
CSSStyleDeclaration.setProperty().
document.createElement().
document.createDocumentFragment().
document.querySelector().
document.querySelectorAll().
Element.append().
Element.classList API.
Element.slot.
HTMLSlotElement.
HTMLTemplateElement.
Node.cloneNode().
Object.prototype.keys().
Bibliography:
How to pass option tags to a custom element as distributed nodes (aka <slot></slot>).
"Using Templates and Slots," MDN.
"Web Components Are Easier Than You Think," CSS-Tricks.
I have been struggling with this for days, I have a function that takes in an object and loops through it creating rows with display columns in it (bootstrap), so I am using jQuery in order to select an id with a value from the object itself and appending to it, but for some reason the id selector that contains the variable is not seen and does not append to the div with the id?
function add_to_page(product) {
//this is the main row that will contain the columns
var rows = $('<div class="row" ></div>');
for (var category in products) {
for (var i = 0; i < products[category].length; i++) {
rows.append($("<div id='" +products[category][i].id +"'></div>").html($('<img>').attr('src', products[category][i].img)));
//the below code is never executed it only creates the image and stops appending after that
$('#' + products[category][i].id).append($('<div class=name>').text(products[category][i].name));
$('#' + products[category][i].id).append($('<div class=category>').text(products[category][i].category));
$('#' + products[category][i].id).append($('<div class=price>').text('Price: ' + products[category][i].price + 'L.E'));
$('#' + products[category][i].id).addClass('col-md-3');
//the below code is to create a new row after filling each row with 4 display columns
if ( i % 3 == 0 && i != 0 ) {
$('#content').append(rows.clone(true));
rows = $('<div class="row"></div>');
}
}
}
}
here is the html i am trying to append to:
<div class="container full-width">
<div id="content"></div>
</div>
i am calling the function normally , no error in the console
add_to_page(products);
You cannot use a selector to find an element you have not yet added to the document (unless you use the second argument of $(selector, context)). But for your purposes, you can just use the fact that the append method can accept more than one argument.
With some other changes to make your code more jQuery-like, you get this:
function add_to_page(products) {
//this is the main row that will contain the columns
var rows = $('<div>').addClass("row");
for (var category in products) {
for (var item of products[category]) {
rows.append(
$("<div>").attr("id", item.id).addClass('col-md-3').append(
$('<img>').attr('src', item.img),
$('<div>').addClass('name').text(item.name),
$('<div>').addClass('category').text(item.category),
$('<div>').addClass('price').text('Price: ' + item.price + 'L.E')
)
);
//the below code is to create a new row after filling each row with 3 display columns
if ( rows.children().length >= 3 ) {
$('#content').append(rows);
rows = $('<div>').addClass("row");
}
}
}
// Flush any rows that were not yet added:
if ( rows.children().length ) {
$('#content').append(rows);
}
}
// Sample data
var products = {
fruit: [{
name: 'apple',
price: 2.20,
img: "https://www.colourbox.com/preview/7011130-apples-on-table-and-knife.jpg",
category: 'fruit'
}, {
name: 'kiwi',
price: 3.10,
img: "https://www.colourbox.com/preview/10157893-kiwi-fruit.jpg",
category: 'fruit'
}, {
name: 'banana',
price: 1.50,
img: "https://www.colourbox.com/preview/6294218-banana.jpg",
category: 'fruit'
}],
vegetables: [{
name: 'lettuce',
price: 0.90,
img: "https://www.colourbox.com/preview/2347661-fresh-salad-leaves-assortment-in-a-basket.jpg",
category: 'vegetables'
}, {
name: 'radish',
price: 1.60,
img: "https://www.colourbox.com/preview/3602479-red-radish.jpg",
category: 'vegetables'
}]
};
add_to_page(products);
.col-md-3 { display: inline-block; margin: 5px }
img { max-width: 100px }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container full-width">
<div id="content"></div>
</div>
Append all your dynamic html to an element stored in a variable then append that variable to the DOM. that selector wont work bc the element you are trying to access doesnt exists yet.
Do something like:
var el = $('<div' + id + '></div>')
el.append(your row constructed html)
Then append that to your rows at the end of the 2nd for loop.
EDIT
for(.... row iteration code) {
var el = $('<div' + id + '></div>');
el.append('your image goes here');
el.append('name element');
...
rows.append(el);
}
Use #trincot's superior answer, but note that you can also pass an entire HTML string into jQuery's .html(). E.G:
function add_to_page(products) {
var $content = $("#content"),
cols=3, //number of columns
$row,
i=0;
for (var category in products) {
for (var item of products[category]) {
if(i%cols == 0){//add a new row
$row = $("<div class='row'></div>");
$content.append($row);
}
//add the item to the row
$row.append($("<div class='col-md-"+cols+"' id='" +item.id +"'><img src='"+item.img+"' /><div class=name>"+item.name+"</div><div class=category>"+item.category+"</div><div class=price>Price: "+item.price+"L.E</div>"));
i++;
}
}
}
var products = {
"jam" : [
{"id":1,"name":"strawberry", "category":"jam", "price":123, "img":"pic.gif"},
{"id":2,"name":"rasberry", "category":"jam", "price":456, "img":"pic.gif"},
{"id":3,"name":"madberry", "category":"jam", "price":123, "img":"pic.gif"},
{"id":4,"name":"sadberry", "category":"jam", "price":456, "img":"pic.gif"}
],
"bees" : [
{"id":4,"name":"baz", "category":"bee", "price":1, "img":"pic.gif"},
{"id":5,"name":"buzz", "category":"bee", "price":2, "img":"pic.gif"}
]
};
//console.log(products);
add_to_page(products);
.row {display:block; border:1px solid blue;}
.row div[id] {display:inline-block; border:1px solid red; width:100px; margin:5px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container full-width">
<div id="content"></div>
</div>
You need to restructure the code.. are you able to find the element first
rows.append($("")
Instead use products.category [i].id then use jQuery wrap () to wrap the columns to row .
I have a list of cars:
cars = [
{model: "BMW", count: 23, details: "<p>I like <b>X6</b> from Germany</p>"},
{model: "Hyundai", count: 30, details: "<p>I have <b>Verna</b> from Korea</p>"},
{model: "Toyota", count: 08, details: "<p>Small <b>Yaris</b> from Japan</p>"},
{model: "Fiat", count: 12, details: "<p>Latest <b>500c</b> from Italy</p>"}
]
What I'm trying to do is:
The list should always be displayed in a three column layout, also in the case of, for
instance, only four models in total.
List should be ordered alphabetically.
Clicking on each car, model should display additional information about the car (some html) as listed above.
The number of cars in the list can vary at any moment.
I'm trying to get my head around these requirements while I'm learning JS. I like to understand the thinking process about each step in order to learn correctly.
Here is an example that may solve your requirements:
1) As I mentioned in a comment, There is an html table with three columns.
2) Sorts cars by model name.
3) When the models are clicked, additional information is displayed about the car. (in this case, in an alert window)
4) You can add cars to the list with the form, and the table is then regenerated.
Run code here.
<html>
<head>
<title>Just for fun</title>
</head>
<body>
<h3>Cars and types:</h3>
<form name="myForm" onsubmit="return mysubmit()">
Model: <input type="text" name="model"><br>
Count: <input type="text" name="count"><br>
Details: <input type="text" name="details"><br>
<input type="submit" value="Submit">
</form>
<button onclick="generate_table()">Generate Table</button><br>
<table class="cars">
</table>
<div class="details" style="float:right;">
</div>
<script>
console.log('script started');
var cars = [
{model: "BMW", count: 23, details: "<p>I like <b>X6</b> from Germany</p>"},
{model: "Hyundai", count: 30, details: "<p>I have <b>Verna</b> from Korea</p>"},
{model: "Toyota", count: 08, details: "<p>Small <b>Yaris</b> from Japan</p>"},
{model: "Fiat", count: 12, details: "<p>Latest <b>500c</b> from Italy</p>"}
]
var types = ["model","count","details"];
function generate_table() {
cars.sort(compare);
var body = document.getElementsByTagName("body")[0];
// creates a <table> element and a <tbody> element
var tbl = document.getElementsByClassName("cars")[0];
tbl.innerHTML = '';
var tblBody = document.createElement("tbody");
console.log(cars.length);
for (var i = 0; i < 3; i++) {
var index = ((j*3)+i);
if (index < cars.length) {
// Create a <td> element and a text node, make the text
// node the contents of the <td>, and put the <td> at
// the end of the table row
var cell = document.createElement("td");
var num = index;
cell.innerHTML = '' + cars[index][types[0]] + ' (' + cars[index][types[1]] + ')';
row.appendChild(cell);
}
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "2");
}
// This function throws details into 'details' div
function showDetails(num) {
console.log('details showing',num);
div = document.getElementsByClassName('details')[0];
div.innerHTML = '';
var car = cars[num];
div.innerHTML = 'Model: ' + car.model + '</br>Count: ' + car.count +
'</br>Details:\t' + car.details;
}
function mysubmit() {
var model = document.forms["myForm"]["model"].value
var count = document.forms["myForm"]["count"].value
var details = document.forms["myForm"]["details"].value
cars.push({
model:model,
count:count,
details:details
});
generate_table();
return false;
}
function compare(a,b) {
if (a.model < b.model)
return -1;
if (a.model > b.model)
return 1;
return 0;
}
</script>
</body>
</html>
EDIT: Changed code to throw details into div instead of alert box - this way you can see the HTML being run.
EDIT2: Shows cars in 3 columns.
References:
Sorting Function
generate_table function [slightly modified]