Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 months ago.
Improve this question
I would like to create a menu from multiple JSON files.
Please see the following: https://jsfiddle.net/varJSFiddle/teghqov0/10/
The desired output would be a dynamic menu that looks something like:
<ul class="filter-menu-wrapper">
<li class="filter-menu is-active" id="filter-menu_01"><span class="filter-category">Type<i class='cstm-icon-glyph cstm-icon-glyph-plus'></i></span>
<div class="filter-options">
<span class="filter-option" data-filter="">any</span>
<span class="filter-option" data-filter=".TypeHuman">Human</span>
<span class="filter-option" data-filter=".TypeBlue">Blue</span>
<span class="filter-option thefirst" data-filter=".TypeRed">Red</span>
<span class="filter-option" data-filter=".TypeSpirit">Spirit</span>
</div>
</li>
<li class="filter-menu" id="filter-menu_02"><span class="filter-category">Special<i class='cstm-icon-glyph cstm-icon-glyph-plus'></i></span>
<div class="filter-options">
<span class="filter-option" data-filter="">any</span>
<span class="filter-option" data-filter=".SpecialFireflies">Fireflies</span>
<span class="filter-option" data-filter=".SpecialButterfly">Butterfly</span>
<span class="filter-option" data-filter=".SpecialFoxFire">Fox Fire</span>
<span class="filter-option" data-filter=".SpecialSmoke">Smoke</span>
<span class="filter-option" data-filter=".SpecialSakura">Sakura</span>
<span class="filter-option" data-filter=".SpecialFire">Fire</span>
<span class="filter-option" data-filter=".SpecialEarth">Earth</span>
<span class="filter-option" data-filter=".SpecialWater">Water</span>
<span class="filter-option" data-filter=".SpecialLightning">Lightning</span>
</div>
</li>
<li class="filter-menu" id="filter-menu_03"><span class="filter-category">Clothing<i class='cstm-icon-glyph cstm-icon-glyph-plus'></i></span>
<div class="filter-options">
<span class="filter-option" data-filter="">any</span>
<span class="filter-option" data-filter=".ClothingLightKimono">Light Kimono</span>
<span class="filter-option" data-filter=".ClothingMaroonYukata">Maroon Yukata</span>
<span class="filter-option" data-filter=".ClothingBlueKimono">Blue Kimono</span>
<span class="filter-option" data-filter=".ClothingGreenYukata">Green Yukata</span>
</div>
</li>
</ul>
i think you need like below output , try it, comment if query
$(document).ready(function() {
// 1.) create an attributes (trait) array
// 2.) loop through the items, check if the trait is already in the array, if not then add it
// 3.) loop over attributes array and create the menu items off that.
var loopFunction = function(dataIsLoading) { // the loop
var itemURI = "https://ikzttp.mypinata.cloud/ipfs/QmQFkLSQysj94s5GvTHPyzTxrawwtjgiiYS2TBLgrvw8CW/"
var myArray = []; // create an array to capture all traits
for (let i = 0; i < 4; i++) {
$.getJSON(itemURI+i, function(data) {
var menuItems = "";
var headings = "";
var subheadings = "";
var dataFilter = "";
$.each(data.attributes,function(index,entry) { // i (index), e (entry)
headings = entry.trait_type;
subheadings = entry.value;
dataFilter = entry.trait_type + entry.value;
dataFilter = dataFilter.replace(/ /g, '');
menuItems += '<li class="category"><b>' + headings + '</b>: <br/> ';
menuItems += subheadings + ', ';
menuItems += dataFilter;
menuItems += '</li>'
myArray += entry.trait_type + ': ' + entry.value;
});
$('#myList').html(menuItems);
$('#dump').html(myArray);
//console.log(myArray);
});
}
};
$.when(loopFunction()).done(function() {
var secondaryFunction = function(secondary) { // the loop
// alert("it's done, sort and display");
}
secondaryFunction();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id ="myList">
</ul>
MAYUR, I ended up with the following. It works perfectly however it is a little slow. If you have any tips on improving the speed, let me know:
$(document).ready(function() {
// 1.) create an attributes (trait) array
// 2.) loop through the items, check if the trait is already in the array, if not then add it
// 3.) loop over attributes array and create the menu items off that.
var getItemData = async function(id) {
const itemURI = "https://ikzttp.mypinata.cloud/ipfs/QmQFkLSQysj94s5GvTHPyzTxrawwtjgiiYS2TBLgrvw8CW/"
return await $.getJSON(itemURI+id);
}
var loopFunction = async function(dataIsLoading) {
var items = {};
var promises = [];
for (let i = 0; i < 1000; i++) {
// Get data and add to promises array:
promises.push(getItemData(i));
}
// Wait on all promises:
return await Promise.all(promises).then(function(promise) {
// Loop over each returned promise:
$.each(promise, function(index, data) {
// Loop over attribute data:
$.each(data.attributes, function(index, entry) {
let menuParent = entry.trait_type;
let menuChild = entry.value;
let menuParentItem = {};
// Check for menuParent:
if (items.hasOwnProperty(menuParent)) {
// Get menuParent:
menuParentItem = items[menuParent];
}
// Check for menuChild:
if (!menuParentItem.hasOwnProperty(menuChild)) {
// Add menuChild:
menuParentItem[menuChild] = menuChild;
}
// Update items object:
items[menuParent] = menuParentItem;
});
});
// Return items.
return items;
});
};
$.when(loopFunction()).done(function(items) {
// Loop over all items creating the markup.
var menuItems = '';
$.each(items, function(menuParent, menuChildren) {
menuItems += '<li class="menuParent"><b>' + menuParent + '</b>: <ul>';
// Loop over menuChildren.
$.each(menuChildren, function(menuChild, menuChildValue) {
menuItems += '<li class="menuChild">' + menuChild + '</li>';
});
menuItems += '</ul></li>';
});
// Render menu items.
$('#myList').append(menuItems);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id ="myList">
</ul>
Related
This is the code from telmo sampiao's shopping cart series, im missing remove items and increment/decrement buttons while also including it on local storage.
function displayCart(){
let cartItems = localStorage.getItem("productsInCart");
cartItems = JSON.parse(cartItems);
let productContainer = document.querySelector(".products");
let cartCost = localStorage.getItem('totalCost');
console.log(cartItems);
if( cartItems && productContainer){
productContainer.innerHTML = '';
Object.values(cartItems).map(item => {
productContainer.innerHTML += `
<div class="product">
<button class="btn btn-danger remove">Remove</button>
<img src="./img/${item.tag}.jpg">
<span>${item.name}</span>
</div>
<div class="price">
₱${item.price}.00
</div>
<div class="quantity"><i class="fa-solid fa-plus"></i> <span>${item.inCart}</span> <i class="fa-solid fa-minus"></i></div>
<div class="total">
₱${item.inCart * item.price}.00
</div>
`
});
productContainer.innerHTML += `
<div class="basketTotalContainer">
<h4 class="basketTotalTitle">
Cart Total
</h4>
<h4 class="basketTotal">
₱${cartCost}.00
</h4>
`;
}
}
Im not good at javascript I tried many diffrenet things but doesnt work
You only store one value for several different inputs. You need to identify each value for each input seperately.
HTML
Add a unique attribute "data-key". Or you can use the "id" of each element.
<div class="item">
<button class="plus" data-qty="1">+</button>
<input class="count" data-qty="1" type="number" min="1" max="5" value="1" data-key="myInput1"> <!-- add a unique key -->
<button class="minus" data-qty="1">-</button>
+
-
Jquery
I altered your code. See comments below. Now "data-key" is used as key for the localStorage.
<script>
let itemData = {
itemQty: 1
};
if (localStorage.getItem("itemData") === null) {
localStorage.setItem("itemData", JSON.stringify(itemData));
}
// new code for initializing
// parse all inputs and user their keys to find the corresponding itemdata
var allinputs = $('.count');
for (var i = 0; i < allinputs.length; i++) {
// get data according to "data-key"
var getItem = loadQuantity($(allinputs[i]).attr('data-key'));
if (getItem != null) {
$(allinputs[i]).val(getItem.itemQty);
} else {
// data not existing. Set global default value
saveQuantity(JSON.stringify(itemData), $(allinputs[i]).attr('data-key')); // *1 set first parameter just to itemData
}
}
$(".plus").click(function () {
// use key to get itemdata of this input
var keyOfInput = $(this).closest(".item").find(".count").attr('data-key');
var getItem = loadQuantity(keyOfInput);
getItem.itemQty = getItem.itemQty + 1;
saveQuantity(getItem, keyOfInput);
$(this).closest(".item").find(".count").val(getItem.itemQty);
});
$(".minus").click(function () {
// use key to get itemdata of this input
var keyOfInput = $(this).closest(".item").find(".count").attr('data-key');
var getItem = loadQuantity(keyOfInput);
if(getItem.itemQty != 1){
getItem.itemQty = getItem.itemQty - 1;
}
saveQuantity(getItem, keyOfInput);
$(this).closest(".item").find(".count").val(getItem.itemQty);
});
// added new parameter "key"
function saveQuantity(data, key) {
localStorage.setItem(key, JSON.stringify(data));
}
function loadQuantity(key) {
return JSON.parse(localStorage.getItem(key)); // *2 Change to JSON.parse(JSON.parse(localStorage.getItem(key)));
}
I need populate <li> using javascript. I tried this.
ASPX code:
<div class="col-xs-12" id="displayDiv" runat="server">
<ul id="servicesList" runat="server"></ul>
</div>
JavaScript:
function PopulateList() {
var json = "[ { \"Id\":1068, \"Name\":\"Doe\" }, { \"Id\":1070, \"Name\":\"Smith\" },{ \"Id\":1074, \"Name\":\"Jones\" } ]";
var obj = JSON.parse(json);
var list = document.getElementById('<%= servicesList.ClientID %>');
for (i = 0; i < obj.length; i++) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(obj[i].Name));
li.className = "drag-handle-container";
li.innerHTML = "<i class='fa fa-bars'></i>";
li.setAttribute("data-id", obj[i].Id);
list.appendChild(li);
}
}
But it's not populated I expected a list with SPAN I need this
<ul id="ctl00_ContentPlaceHolder1_servicesList">
<li class="sortable-service-item"><span class="drag-handle-container"><i class="fa fa-bars"></i></span><span style="display: none;">1068</span><span>Doe</span></li>
<li class="sortable-service-item"><span class="drag-handle-container"><i class="fa fa-bars"></i></span><span style="display: none;">1070</span><span>Smith</span></li>
<li class="sortable-service-item"><span class="drag-handle-container"><i class="fa fa-bars"></i></span><span style="display: none;">1074</span><span>Jones</span></li>
</ul>
According to my code, HTML generating as follows, but I need the above HTML
<ul id="ctl00_ContentPlaceHolder1_ViewProductService_servicesList">
<li class="drag-handle-container" data-id="1068"><i class="fa fa-bars"></i></li>
<li class="drag-handle-container" data-id="1070"><i class="fa fa-bars"></i></li>
<li class="drag-handle-container" data-id="1074"><i class="fa fa-bars"></i></li>
</ul>
How to populate above HTML code by using javascript for loop?
You are requesting a way to achieve your "above" HTML (as you mentioned) but your generated code is vastly different than that. There are "data-ids" , different class-names , etc. Nevertheless , taking for granted that your "above" code is your goal the following 2 ways will produce exactly that. The first way follows your path. Using Native Javascript createElement functions and appending them on DOM elements. The Second way creates a String that represents HTML Code and it inserts it into the DOM creating the whole List.
In both examples i use the Array.prototype.forEach() for the Array loops and the
Object.keys() for the Object loops. I also use Arrow functions in those loops which is not necessary though in this case.
1st Way
let json = "[ { \"Id\":1068, \"Name\":\"Doe\" }, { \"Id\":1070, \"Name\":\"Smith\" },{ \"Id\":1074, \"Name\":\"Jones\" } ]";
let obj = JSON.parse(json);
let list = document.getElementById('servicesList');
obj.forEach((ObjectRow)=>{
let li = document.createElement("li");
li.className = "sortable-service-item";
let Span = document.createElement("span");
Span.className = "drag-handle-container";
Span.innerHTML = "<i class='fa fa-bars'></i>";
Span.setAttribute("data-id", ObjectRow["Id"]);
li.appendChild(Span);
Object.keys(ObjectRow).forEach((key)=>{
let tempSpan = document.createElement("span");
tempSpan.innerHTML = ObjectRow[key];
li.appendChild(tempSpan);
});
list.appendChild(li);
});
2nd Way
let json = "[ { \"Id\":1068, \"Name\":\"Doe\" }, { \"Id\":1070, \"Name\":\"Smith\" },{ \"Id\":1074, \"Name\":\"Jones\" } ]";
let obj = JSON.parse(json);
let list = document.getElementById('servicesList');
let myHTML;
obj.forEach((ObjectRow)=>{
myHTML += "<li class='sortable-service-item'>" +
"<span class='drag-handle-container' data-id='"+ObjectRow["Id"]+"'>" +
"<i class='fa fa-bars'></i>" +
"</span>";
Object.keys(ObjectRow).forEach((key)=>{
myHTML += "<span>"+ObjectRow[key]+"</span>";
});
myHTML += "</li>";
});
list.insertAdjacentHTML("beforeEnd" , myHTML);
Please try updated code:
Change the value inside the for loop as per your requirement.
for (i = 0; i < 3; i++) {
var li = document.createElement("li");
li.className = "drag-handle-container";
var span_1 = document.createElement("span");
span_1.setAttribute('class', 'drag-handle-container');
span_1.innerHTML = '<i class="fa fa-bars"></i>';
li.appendChild(span_1);
var span_2 = document.createElement("span");
span_2.style.display = 'none';
span_2.innerHTML = '1068';
li.appendChild(span_2);
var span_3 = document.createElement("span");
span_3.innerHTML = 'Doe';
li.appendChild(span_3);
console.log(li);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I need to call same api with different product id so i can compare two product details , how i can send two different id to same api .
Here is my click function with
<div class="hmpal-prprt-post-wdgt hmpal-prprt-compare"
ng-click="compareProjects(project.property_id)"
ng-repeat="project in properties"><a href="">
<span class="prprt-icon">
<i class="fa fa-balance-scale" aria-hidden="true"></i>
</span>
<span>Compare</span></a>
I think I understand your requirement. You want to compare 2 items chosen by the user, let's say your have items A,B,C,D and the user can choose to compare B and D.
This is actually more of a UI/UX problem instead of programming problem.
This is one of the designs I can think of
angular.module('test', []).controller('Test', TestController);
function TestController($scope) {
$scope.items = ["A", "B", "C", "D"];
$scope.selected1 = "";
$scope.selected2 = "";
$scope.compare = "";
$scope.select = function(item) {
// first select
if (!$scope.selected1) {
$scope.selected1 = item;
return;
}
// second select
if (!$scope.selected2) {
if ($scope.selected1 == item) {
$scope.selected1 = "";
return;
}
else {
$scope.selected2 = item;
compare();
return;
}
}
// back to first select again
$scope.selected1 = item;
$scope.selected2 = "";
}
function compare() {
$scope.compare = "comparing '" + $scope.selected1 + "' and '" + $scope.selected2 + "'";
}
}
.selected {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<div ng-repeat="item in items"
ng-class="{'selected': item == selected1 || item == selected2}"
ng-click="select(item)">
{{item}}
</div>
<br>
<div>{{compare}}</div>
</div>
The following code works, but I think there's room for improvement. The index check is there because after the first element is removed the next element looks like it has an index of -1, but is actually the previously removed element. Then it iterates again and finds the clicked element and removes it. BUT since the index is -1 on the first go around the wrong group gets deleted.
How do I keep the zombie elements from being iterated on more efficiently? This is in a backbone view with an in page confirmation.Thanks.
EDIT: To add HTML
Group section always has a default group that shouldn't be deleted.
<div class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>All Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div><!--/expandable__content-->
Tag section to remove groups
<div class="js-favorite-doctor-manage-add-remove">
<div class="grid-construct">
<div class="expandable" data-controller="expandable">
<ul class="tag-list js-group-list" tabindex="-1">
<li class="tag tag--teal" >
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li class="tag tag--teal" >
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
</ul>
</div>
removeGroup: function( evt ) {
var deleteGroup = function() {
if ( $(evt.currentTarget).closest('.tag').hasClass('is-active')){
var clickedTag = $(evt.currentTarget).closest('.tag');
var groupList = this.$el.find('.js-group-list');
var groupTags = groupList.find('.tag');
var index = groupTags.index(clickedTag);
var groupSections = $('.js-favorite-group');
// add one to account for "All" section which is never removed
var groupToRemove = groupSections.eq(index + 1);
console.log(groupToRemove);
var removedGroupName = this.getGroupNameForSection(groupToRemove);
var allDoctors = groupSections.eq(0);
var allDoctorsContainer = allDoctors.find('.js-favorite-doctor-row-container');
if ( index > -1 ){
groupToRemove.find('.js-favorite-doctor-row').appendTo(allDoctorsContainer);
clickedTag.remove();
groupToRemove.remove();
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
};
this.showAlert(evt, deleteGroup);
},
showAlert: function (evt, callback) {
that = this;
var clickedTag = '';
clickedTag = $(evt.currentTarget).closest('.tag');
clickedTag.addClass('is-active').attr('data-delete','true');
$('.delete-acct-message').show().focus();
$('.js-remove-yes').on('click', function(evt){
evt.preventDefault();
callback.apply(that);
});
$('.js-remove-no').on('click', function(evt){
evt.preventDefault();
this.hideConfirm(evt);
});
},
I would suggest that you should use custom attributes in your html, this will simplify your javascript logic and make it more effective and efficient.
I have modified your html and javascript to add the support for custom attribute data-doc-group. Have a look at your group sections div here
<div data-doc-group="lauren" class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>Lauren's Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div>
Here are the tags with custom attributes
<li data-doc-group="lauren" class="tag tag--teal">
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li data-doc-group="timmy" class="tag tag--teal">
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
Here is the javascript to handle this, (this may be a bit buggy, but will give you a general idea)
removeGroup: function(evt) {
this.showAlert(evt, function() {
var $clickedTag = $(evt.currentTarget).closest('.tag'),
dataGroupName,
$groupToRemove,
removedGroupName,
$allDoctors = $('.js-favorite-group').eq(0),
$allDoctorsContainer = $allDoctors.find('.js-favorite-doctor-row-container');
if ($clickedTag.hasClass('is-active')){
dataGroupName = $clickedTag.data('doc-group');
$groupToRemove = $allDoctors.siblings('[data-doc-group="' + docGroupName + '"]');
if ($groupToRemove.length > 0){
$groupToRemove.find('.js-favorite-doctor-row').appendTo($allDoctorsContainer);
$clickedTag.remove();
$groupToRemove.remove();
removedGroupName = this.getGroupNameForSection($groupToRemove);
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
});
}
I have a JSON witch looks something like this
{
"English": "en",
"Francais": "fr",
"German": "gm"
}
Now I need to print this data in HTML structure witch looks like this
<ul id="links">
<li class="home">
</li>
<li class="languages">
EN ------ > FIRST LANGUAGE FROM JSON
<ul class="available"> ----> OTHERS
<li>DE</li>
<li>IT</li>
<li>FR</li>
</ul>
</li>
</ul>
In javascript I know how to get data and print all data in the same structure but how to do it in structure shown in example ?
in Javascript I'm getting data with
$.getJSON('js/languages.json', function(data) {
console.log(data);
/* $.each(data, function(key, val) {
console.log(val);
});*/
});
Use jQuery template to bind the Html. Some Sample
Something like that:
var getBlock = function(skipLang) {
var str = '\
<ul id="links">\
<li class="home">\
\
</li>\
<li class="languages">\
' + data[skipLang] + '\
<ul class="available">\
';
for(var lang in data) {
if(lang != skipLang) {
str += '<li>' + lang + '</li>';
}
}
str += '</ul></li></ul>';
return str;
}
var html = '';
for(var lang in data) {
html += getBlock(lang);
}
Although using templating engine is an option for simpler code, for this case you can directly run a for loop and assign HTML within javascript code easily.
HTML part is going to be something like this
<ul id="links">
<li class="home">
home
</li>
<li class="languages">
<ul class="available">
</ul>
</li>
</ul>
And JS part is like this:
var data = {
"English": "en",
"Francais": "fr",
"German": "gm"
};
var $liLanguages = $('li.languages');
var $ulAvailable = $('ul.available');
var selectedLanguage = '';
for(var index in data) {
if(selectedLanguage == '') {
selectedLanguage = data[index];
$liLanguages.prepend("<a href='#'>" + data[index].toUpperCase() + "</a>");
}
else {
$ulAvailable.append("<li><a href='#'>" + data[index].toUpperCase() + "</a></li>");
}
}
Here is the jsfiddle related.
Hope this helps.
Here is a bit that will get you two new objects, one for the first object property/value and another for the remaining. Still not clear what is done with it once you have it, but let me know if it helps:
// This can be replaced with existing data or updated to var langs = data;
var langs = {"English": "en", "Francais": "fr","German": "gm" };
// jQuery map only works on objects after 1.6, heads up
var lang_keys = $.map( langs, function( value, key ) {
return key;
});
// Now that you have an array of the keys, you can use plain-ol shift()
var primary_lang_key = lang_keys.shift();
// create and populate an object just for your first language:
var primary_lang = {};
primary_lang[primary_lang_key] = langs[primary_lang_key];
// Thanks to shift, we know that populating this object with lang_keys will
// only have remaining items:
var other_langs = {};
$.map( lang_keys, function( lang_key ) {
other_langs[lang_key] = langs[lang_key];
});
console.log(other_langs);