Dynamic Menu from multiple JSON files [closed] - javascript

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

How can I add remove items and increment the quantity and increase the price while incrementing or decrementing the quantity of my cart. code by telmo

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)));
}

How to add mutiple span to <li> javascript

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>

how to implement comparison of two products on ng-click in angular?

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>

Losing context in callback when invoked the second time backbone

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);
}
}
});
}

Print JSON data in HTML structure issue

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);

Categories

Resources