I am searching on nested objects. I want to render objects properties but every time i have to go in object like mobiles.apple.iphone12.properties. I have multiple mobiles in object if i do like that it will be very lengthy code. I just want to print in shorter way. Check out the JavaScript code below.
let searchBtn = document.getElementById('search-btn')
let mobiles = {
apple: {
iphone13: {
model: 'iphone 13',
color: 'black',
price: 1000,
camera: 20,
battery: 500,
},
iphone12: {
model: 'iphone 12',
color: 'red',
price: 800,
camera: 15,
battery: 400,
src: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRhdp92UKK3NxwNfcIBlyZX8g26kEYBG3WNoQ&usqp=CAU"
}
},
samsung: {
s10: {
model: 'Samsung S10',
color: 'black',
price: 500,
camera: 10,
battery: 600,
},
a10: {
model: 'Samsung A10 ',
color: 'blue',
price: 300,
camera: 20,
battery: 150,
}
},
moto: {
motoz: {
model: 'Moto Z',
color: 'black',
price: 500,
camera: 10,
battery: 300,
},
motoe4: {
model: 'Moto E4',
color: 'black',
price: 200,
camera: 10,
battery: 300,
}
},
techno: {
camon18: {
model: 'Camon 18',
color: 'golden',
price: 5000,
camera: 10,
battery: 300,
},
spark7: {
model: 'Spark 7',
color: 'sky blue',
price: 2000,
camera: 10,
battery: 300,
}
}
}
searchBtn.addEventListener('click', function () {
let brandName = document.getElementById('brand-name').value
let modelName = document.getElementById('model-name').value
if (mobiles[brandName] !== undefined) {
if (mobiles[brandName][modelName] !== undefined) {
console.log(mobiles[brandName][modelName])
}
else {
console.log('This model is not available')
}
}
else if (brandName == '' || modelName == '') {
console.log('Brand name OR Model name is empty')
}
else {
console.log('This model is not available')
}
})
let card = `<div >
<img src="${mobiles.apple.iphone12.src}" style="width:100%">
<h1> ${mobiles.apple.iphone12.model} </h1>
<p > Rs: ${mobiles.apple.iphone12.price}</p>
<p> Color: ${mobiles.apple.iphone12.color} </p>
<p> Battery: ${mobiles.apple.iphone12.battery} </p>
<p><button>Add to Cart</button></p>
</div>`
document.getElementById("container").innerHTML = card
#container {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.card {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
width: 300px;
margin: 50px;
text-align: center;
font-family: arial;
}
img {
margin-top: 20px;
}
.price {
color: grey;
font-size: 22px;
}
.card button {
border: none;
padding: 12px;
color: white;
background-color: #000;
text-align: center;
cursor: pointer;
width: 100%;
font-size: 18px;
}
.card button:active {
opacity: 0.7;
}
<input type="text" id="brand-name" placeholder="Enter Brand Name">
<input type="text" id="model-name" placeholder="Enter Model Name">
<button id="search-btn">Searh Phone</button>
<div id="container"> </div>
CodePudding user response:
So from my understanding you are trying to create the initial displayed items.
You can have a generic function that generates the cards filtered or unfiltered.
const generateCards = (brand = '', model = '') => {
const fragment = document.createDocumentFragment();
Object.entries(mobiles)
.filter(([key]) => key.includes(brand))
.forEach(([, mobile]) => {
Object.entries(mobile)
.filter(([key]) => key.includes(model))
.forEach(([, model])=> {
const card = document.createElement('div');
card.classList.add('card');
card.innerHTML = `${model.src ? ('<img src=' model.src '} style="width:100%">') : ''}
<h1> ${model.model} </h1>
<p > Rs: ${model.price}</p>
<p> Color: ${model.color} </p>
<p> Battery: ${model.battery} </p>
<p><button>Add to Cart</button></p>`;
fragment.appendChild(card)
})
})
document.getElementById("container").innerHTML = fragment;
}
Then you can call generateCards()
initially and it will generate all of the cards, and on the listeners for the brand and model you just call it with those values generateCards(brand, model)
CodePudding user response:
I'm assuming, reading your question, that you want a user to search for a brand/model and get as output the device specs (if present).
If so, first thing you should do is to put the creation of the card inside your eventlistener definition, otherwise you won't be able to render any of them.
I made some changes in the snippet below; in this case you don't have to create card
specifying model and brand in advance.
searchBtn.addEventListener('click', function () {
let brandName = document.getElementById('brand-name').value;
let modelName = document.getElementById('model-name').value;
if (!mobiles[brandName] || brandName == '') {
console.log('Brand not available');
return;
}
if (!mobiles[brandName][modelName] || modelName == '') {
console.log('Model not available');
return;
}
console.log(mobiles[brandName][modelName]);
// Clear previous search
document.getElementById('container').innerHTML = null;
document.getElementById('container').innerHTML = getMobileinfoHtmlElement(
mobiles[brandName][modelName]
);
});
function getMobileinfoHtmlElement(mobile) {
return `<div >
<img src="${mobile.src}" style="width:100%">
<h1> ${mobile.model} </h1>
<p > Rs: ${mobile.price}</p>
<p> Color: ${mobile.color} </p>
<p> Battery: ${mobile.battery} </p>
<p><button>Add to Cart</button></p>
</div>`;
}
This code works if you are going to use nested objects. Speaking about best practice, arrays should be better; they have pre-built methods like .filter()
or .find()
that can be useful in this case.