Jquery append an array of object values to the right div - javascript

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.

Related

Tagify removes the tag but still remains in the textarea

I have aproblem with tagify. When I remove a tag (using tag cross), visually the tag is removed from the text area but then it is passed as a parameter via ajax. For example, if I have the following text:
Vito hello
and Vito is a tag, if I delete it, visually only hello remains but still if I send the text taking the text area via jquery still it considers me the text Vito hello.
What is the problem?
EDIT:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BigMouth v1.0</title>
<script src="../jquery.min.js"></script>
<link rel="stylesheet" href="../jquery-ui.min.css">
<script src="../jquery-ui.min.js"></script>
<script src="../tagify"></script>
<script src="../tagify.polyfills.min.js"></script>
<link href="../tagify.css" rel="stylesheet" type="text/css" />
<script src="../bootstrap.js"></script>
<link rel="stylesheet" href="../bootstrap.css">
<script>
function ShareData(){
let datepicker = document.getElementById("datepicker").value;
let oggetto = document.getElementById("oggetto").value;
let descrizione = document.getElementById("descrizione").value;
// list_added_people is a global variable
const ids = list_added_people.map(o => o.id)
// remove duplicates
const filtered = list_added_people.filter(({ id }, index) => !ids.includes(id, index + 1))
let json_form = { 'date': datepicker, 'oggetto': oggetto, 'descrizione': descrizione, 'people': filtered };
ipcRenderer.send('insert_event', JSON.stringify(json_form));
}
</script>
</head>
<body>
<div id="messages"></div>
<div style="display: none;" id="id_people"></div>
<div class="container">
<form id="myForm" action="#">
<div class="row">
<div class="row" id="title_area">
<h1>Inserisci evento:</h1>
</div>
<div class="row" id="date_area">
<div class="col">
<p>Data: <input type="text" id="datepicker"></p>
</div>
</div>
<div class="row" id="object_area">
<div class="col">
<p>Oggetto: <input type="text" id="oggetto" style=" width:50%"></p>
</div>
</div>
<div class="row" id="description_area">
<div class="col">
<p>Descrizione:</p>
<textarea id = "descrizione" name='mix'></textarea>
</div>
</div>
<div class="row" id="buttons_area">
<div class="col-xs-3">
<button type="button" class="btn btn-dark btn-block">Salva</button>
</div>
<div class="col-xs-3">
<button type="button" id = "prova" class="btn btn-danger btn-block">Cancella</button>
</div>
</div>
<button onclick="ShareData()">ShareData</button>
</div>
</form>
</div>
</div>
<style>
#date_area{
margin-top: 30px;
margin-bottom: 10px;
}
#object_area{
margin-top: 30px;
margin-bottom: 10px;
}
#description_area{
margin-top: 50px;
margin-bottom: 10px;
}
#buttons_area{
margin-top: 30px;
margin-bottom: 10px;
}
.delete_btn_area{
margin-left: 30px;
}
</style>
<script>
Array.prototype.containsArray = function (val) {
var hash = {};
for (var i = 0; i < this.length; i++) {
hash[this[i]] = i;
}
return hash.hasOwnProperty(val);
}
$(document).ready(function(){
var whitelist_1;
list_added_people = []
// AGGIUNGE LE PERSONE SALVATE IN DB NEL TAGGIFY
ipcRenderer.send('get_people', "ciao backend");
window.api.receivePeople((data) => {
let people = JSON.parse(data)
for(i in people){
whitelist_1.push({ value: people[i]['id'], text: people[i]['name'] + " " + people[i]['surname'], title: people[i]['name'] + " " + people[i]['surname'] })
}
})
$( function() {
$( "#datepicker" ).datepicker();
});
// Define two types of whitelists, each used for the dropdown suggestions menu,
// depending on the prefix pattern typed (#/#). See settings below.
var whitelist_1 = [
{ value: 100, text: 'kenny', title: 'Kenny McCormick' },
{ value: 1000, text: 'Mr. Mackey', title: "M'Kay" }
]
// Second whitelist, which is shown only when starting to type "#".
// Thiw whitelist is the most simple one possible.
whitelist_2 = ['Homer simpson', 'Marge simpson', 'Bart', 'Lisa', 'Maggie', 'Mr. Burns', 'Ned', 'Milhouse', 'Moe'];
// initialize Tagify
var input = document.querySelector('[name=mix]'),
// init Tagify script on the above inputs
tagify = new Tagify(input, {
// mixTagsInterpolator: ["{{", "}}"],
mode: 'mix', // <-- Enable mixed-content
pattern: /#|#/, // <-- Text starting with # or # (if single, String can be used here)
tagTextProp: 'text', // <-- the default property (from whitelist item) for the text to be rendered in a tag element.
// Array for initial interpolation, which allows only these tags to be used
whitelist: whitelist_1.concat(whitelist_2).map(function(item){
return typeof item == 'string' ? {value:item} : item
}),
dropdown : {
enabled: 1,
position: 'text', // <-- render the suggestions list next to the typed text ("caret")
mapValueTo: 'text', // <-- similar to above "tagTextProp" setting, but for the dropdown items
highlightFirst: true // automatically highlights first sugegstion item in the dropdown
},
duplicates: true,
callbacks: {
add: console.log, // callback when adding a tag
remove: console.log // callback when removing a tag
}
})
// A good place to pull server suggestion list accoring to the prefix/value
tagify.on('input', function(e){
var prefix = e.detail.prefix;
// first, clean the whitlist array, because the below code, while not, might be async,
// therefore it should be up to you to decide WHEN to render the suggestions dropdown
// tagify.settings.whitelist.length = 0;
if( prefix ){
if( prefix == '#' )
tagify.whitelist = whitelist_1;
if( prefix == '#' )
tagify.whitelist = whitelist_2;
if( e.detail.value.length > 1 )
tagify.dropdown.show(e.detail.value);
}
console.log( tagify.value )
console.log('mix-mode "input" event value: ', e.detail)
})
tagify.on('add', function(e){
let name = e.detail.data.text
let id = e.detail.data.value
console.log(list_added_people)
var flag = 0
list_added_people.push({ id: id, title: name })
})
tagify.on('remove', function(e){
let id_deleted_person = e.detail.data.value
console.log("---")
console.log(e)
console.log(list_added_people)
var keyToFind = id_deleted_person;
var person_to_delete = -1;
for (var i in list_added_people) {
if (list_added_people[i].id == keyToFind) {
person_to_delete = i
break; // If you want to break out of the loop once you've found a match
}
}
if (person_to_delete != -1) {
list_added_people.splice(person_to_delete, 1)
console.log(list_added_people)
}
//list_added_people = list_added_people.filter(e => e !== id_deleted_person)
})
})
</script>
</body>
</html>

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>

How can I add HTML class when for loop in 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.

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