How can I add HTML class when for loop in JavaScript - javascript

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.

Related

Selecting item in list and displaying the selected item's information in another div

I am getting JSON data (businesses) from the yelp API. I loop through the data to display the businesses, and want to display more information about the business when clicked on in another div. So far I have:
function display_results(businesses) {
var options = '';
for (var i = 0; i < businesses.length; i++) {
options += '<div class="optbtn" value="' + i + '">' + businesses[i].rating.toFixed(1) + "/5\u2606 " + businesses[i].name + '</div>';
}
$('#businesses').html(options);
$('.optbtn').click(function () {
// index problems
var index = $(this).val();
console.log("index: " + index);
var details = businesses[index];
var info = '';
for (key in details) {
info += key + ': ' + details[key] + '<br>';
}
$('#info').html(info);
});
}
$(function () {
$("#search_bar").autocomplete({
source: "/autocomplete",
minLength: 3,
select: function (event, ui) {
$.ajax({
url: "/business_search",
type: "GET",
data: {
term: ui.item.value
},
success: function (result) {
display_results(JSON.parse(result).businesses);
}
});
}
});
});
<div class="ui-widget">
<label for="search_bar">Business Search: </label>
<input id="search_bar" style="width: 400px;">
</div>
<div class="ui-widget">
Businesses:
<div id="businesses" style="height: 400px; width: 600px; overflow: auto; white-space: pre;"
class="ui-widget-content" />
</div>
<div class="ui-widget">
Info:
<div id="info" style="height: 400px; width: 600px; overflow: auto; white-space: pre;"
class="ui-widget-content" />
</div>
My plan was to set an index value for each div containing a business and then upon click use that value to get the rest of the information to display. My problem is that I seem to not be able to actually get the index value using var index = $(this).val();. I am new to all of this and would love some guidance on where I went wrong!
The main issue in your code is because valid HTML div elements should not have a value attribute to be read through jQuery's val() method. The easy fix for this would be to use data attribute to store the index or id of the related array entity within the HTML.
Also note that there's some other optimisations you can make to the logic to improve it:
Use Array.map() and string interpolation to build the HTML more succinctly
Use a single delegated event handler for all dynamic content
Use Object.entries() to retrieve an array-like object containing the key/value pairs within a given object.
Put CSS rules in an external CSS stylesheet, not inline in HTML
With that said, this should work for you:
jQuery($ => {
let $businesses = $('#businesses');
// handle click on the business rating
$businesses.on('click', '.optbtn', e => {
let index = $(e.currentTarget).data('index');
let business = $businesses.data('response')[index];
$('#info').html(Object.entries(business).map(([k, v]) => `<p>${k}: ${v}</p>`));
});
// update the DOM based on the AJAX response:
let display_results = businesses => $businesses.html(businesses.map((b, i) => `<div class="optbtn" data-index="${i}">${b.rating.toFixed(1)}/5\u2606 ${b.name}</div>`))
// make your Autocomplete/AJAX call here.
// mock AJAX response handler:
let ajaxResponse = [{ rating: 1.11, name: 'Foo', address: '123 Any Street' },{ rating: 2.22, name: 'Bar', address: '456 Any Town' },{ rating: 4.44, name: 'Fizz', address: '789 Any City' },{ rating: 5.00, name: 'Buzz', address: '123 Any Avenue' }];
display_results(ajaxResponse); // build the UI from the dataset
$businesses.data('response', ajaxResponse); // store the response for later use
});
#search_bar {
width: 400px;
}
.ui-widget-content {
width: 600px;
overflow: auto;
margin-bottom: 10px;
}
.ui-widget-content p {
margin: 0 0 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="ui-widget">
<label for="search_bar">Business Search:</label>
<input id="search_bar" />
</div>
<div class="ui-widget">
Businesses:
<div id="businesses" class="ui-widget-content"></div>
</div>
<div class="ui-widget">
Info:
<div id="info" class="ui-widget-content"></div>
</div>

Javascript - printing out variables & objects to HTML

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.

Jquery append an array of object values to the right div

I have an array of objects like this
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
And then I have several divs' with data attribute data-id like this
<div id="TLF" class="c2">
<div id="ttimgs" class="mygalleryx lidf2" data-id="4891"> </div>
</div>
<div id="TLF" class="c2">
<div id="ttimgs" class="mygalleryx lidf2" data-id="4892"> </div>
</div>
Now what I am trying to achieve is to filter the array and the resulting array get the image data source from picture: apply to the image and then append the image to the right div with an identical userpostid in relation to the div data-id attr. eg userpostid=4891 append to dive with data-id = 4891.
So far I have tried the code below but I have problems with it creating images in divs' that don't have identical data-id 's
function checkpics(e) {
var x = parseInt(e);
var appendTLpic = TLPics.filter(element => element.userpostid === x);
$(".lidf2").each(function() {
var thisid = $(this).data('id')
$(TLPics).each(function() {
if (thisid == this.userpostid) {
$('[data-id="' + thisid + '"]').append('<a><img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="' + this.Picture + '" style=" display:inline-block"/></a>');
}
});
});
appendTLpic = [];
}
The first issue you have here is that you're duplicating both the #TLF and #ttimgs id attributes when they must be unique. Change them to classes.
Then you can loop through each .ttimgs element and find() the related object in the array by matching the data-id attribute to the userpostid property, before appending the new img. Try this:
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
$('.ttimgs').each(function() {
var src = TLPics.find(x => x.userpostid === $(this).data('id')).Picture;
$(this).append(`<img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="${src}" />`);
});
.userpictz {
display: inline-block;
/* just for this demo... */
border: 1px solid #C00;
width: 30px;
height: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4891"></div>
</div>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4892"></div>
</div>
After a lot of trial and error this is the code I came up with and it achieved my desired results from my question. this may not be the cleanest of code
var TLPics = [{
id: 2141,
Picture: "/postimg/20181102_134013.jpg",
userpostid: 4891
}, {
id: 2142,
Picture: "/postimg/20181102_134053.jpg",
userpostid: 4891
}, {
id: 2143,
Picture: "/postimg/20181102_133944.jpg",
userpostid: 4892
}]
var x;
var appendTLpic = [];
$(".mygalleryx").each(function () {
x = $(this).data('id')
appendTLpic = TLPics.filter(element => element.userpostid === x);
$(appendTLpic).each(function () {
var src = this.Picture
$(`.lidf2[data-id=${x}]`).append(`<img class="userpictz lazyload imgz xp" alt="" data-views="" data-likes="" src="${src}" />`);
});
});
.userpictz {
display: inline-block;
/* just for this demo... */
border: 1px solid #C00;
width: 30px;
height: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4891"></div>
</div>
<div class="TLF c2">
<div class="ttimgs mygalleryx lidf2" data-id="4892"></div>
</div>
When dealing with asp.net web-forms I would have simply solved this with a nested repeater where i get my images from a data-source controlled by the main repeater's hiddenfeild value. Now because my new application demands I have to use Ajax hense this complication.
So I create for each loop for my div with class .mygalleryx then retrieve each divs data-id. now I filter my array TLPics using my data-id variable x. I then nest a for each function for my new filtered array which I retrieve the picture. Now within my new filtered array each function I append my image to the matching div dat-id using my initial variable x and I am done. I am still learning I do wish to be corrected. But this answer has resolved my issue.

How to choose a selector that has a variable in it? (Javascript, jQuery, DOM)

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 .

JavaScript Autosuggest/Autocomplete with some color text

I'm creating my own auto suggest with my input on HTML with pure JavaScript Standard DOM. I'm trying to code my own without using JavaScript Framework with external json file. This is my code so far:
<input type="text" class="input_data" id="Music_Genre" onKeyUp="suggestMusicGenre(this.value, event)" />
<div id="musicgenre_suggest"></div>
function suggestMusicGenre(key, e) {
var targetelem = document.getElementById('musicgenre_suggest');
var temp_array = [];
// basic style for div element
$("#musicgenre_suggest").css({
'position':'absolute',
'background-color':'#fff',
'width': $("#Music_Genre").css('width'),
'cursor':'pointer',
'border':'1px solid #a4a4a4'
});
$.getJSON('json/musicgenre.json', function(data) {
$.each(data, function(index, value) {
var str = value.toString().toLowerCase();
var findstr = str.match(key.toString().toLowerCase());
var boolIfInsert = (findstr != null) ? temp_array.push(value) : false;
});
var prent = document.createElement('ul');
prent.style.listStyleType = "none";
for(var o in temp_array) {
var chld = document.createElement('li');
var txtchld = document.createTextNode(temp_array[o]);
chld.appendChild(txtchld);
prent.appendChild(chld);
}
targetelem.innerHTML = '';
targetelem.appendChild(prent);
});
}
and this is my json file content:
{
"AL" : "Alternative Music",
"BL" : "Blues",
"CM" : "Classical Music",
"CoM" : "Country Music",
"DM" : "Dance Music",
"EL" : "Easy Listening",
"EM" : "Electronic Music"
}
It works fine but I need to add more functionality in it like Facebook does which automatically making some suggested candidate string makes differ its color among to user already typed like example below:
Is is possible with pure standard JavaScript? or should I use JavaScript Framework then?
You can use jQuery UI auto-complete for this. http://jqueryui.com/autocomplete/
CSS
First, let's decide how out list item will look (this won't be the part of the final code, just to get the idea):
<div class="list_item_container">
<div class="image"><img src="hanks.png"></div>
<div class="label">Tom hanks</div>
<div class="description">Actor</div>
</div>
And the formatting (this should go in your stylesheets):
DIV.list_item_container {
height: 90px;
padding: 5px;
}
DIV.image {
width: 90px;
height: 80px;
float: left;
}
DIV.description {
font-style: italic;
font-size: 0.8em;
color: gray;
}
Javascript
Now, creating the autocomplete and overriding _renderItem() method:
$(function() {
$("#my_ac").autocomplete({
source: [
{
value: "Tom Hanks",
label: "Tom Hanks",
description: "Actor",
image: "hanks.png"
},
{
value: "Termionator 2",
label: "Termionator 2",
description: "Movie",
image: "terminator.png"
}
],
minLength: 1
}).data( "autocomplete" )._renderItem = function( ul, item ) {
var inner_html = '<a><div class="list_item_container"><div class="image"><img src="' + item.image + '"></div><div class="label">' + item.label + '</div><div class="description">' + item.description + '</div></div></a>';
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append(inner_html)
.appendTo( ul );
};
});
Please note, that inner is inside tags. This might not be the proper HTML, but it's the only way to make the whole item clickable.
HTML
Now just create an input with id my_ac and you are done:
<input type="text" id="my_ac" size="40" />
Reference here.

Categories