Parse JSON foreach with JS, shows HTML list - javascript

I am currently trying to parse a JSON with JavaScript. My issue is that I'd like the output to look like this:
<li>AppName1</li>
<li>AppName2</li>
<!-- and so on... -->
However it just does not work and I don't know how to achieve that. This is the object deserialized from the JSON response:
{
"data": [{
"AppId": 1,
"AppName": "AppName1",
"AppSize": "2.1"
}, {
"AppId": 2,
"AppName": "AppName2",
"AppSize": ""
}]
}
This is my .js file:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
document.getElementById("test").innerHTML = myObj.AppName;
}
};
xmlhttp.open("GET", "json.json", true);
xmlhttp.send();
This is in my HTML file
<p id="test"></p>
Any help would be appreciated as I really cannot seem to understand this a single bit. Thank you so much!

Firstly note that you can only have li elements as children of <ul> or <ol>, so the p element needs to be changed.
The AppName property is part of the objects within data, so you will need to either loop through them:
myObj.data.forEach(function(o) {
document.getElementById("test").innerHTML += '<li>' + o.AppName + '</li>';
}
Or access them, individually by index:
document.getElementById("test").innerHTML = '<li>' + myObj.data[0].AppName + '</li>'; // first item only
var myObj = {
"data": [{
"AppId": 3,
"AppName": "AnimojiStudio",
"AppSlug": "animojistudio",
"AppIcon": "https:\/\/img.lmdinteractive.pro\/icons\/animojistudio.png",
"AppUrl": "https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/animojistudio.ipa",
"AppVersion": "1.2.2",
"AppSize": "2.1"
}, {
"AppId": 2,
"AppName": "Cute Cut Pro",
"AppSlug": "cute-cut-pro",
"AppIcon": "http:\/\/is2.mzstatic.com\/image\/thumb\/Purple118\/v4\/03\/70\/69\/03706968-2399-a1d8-e7c4-12897394ead9\/source\/512x512bb.jpg",
"AppUrl": "https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/cutecutpro.ipa",
"AppVersion": "",
"AppSize": ""
}]
}
document.getElementById("test").innerHTML = '<li>' + myObj.data[0].AppName + '</li>';
<ul id="test"><li>

If you just want a list of the AppName properties, you could do something like the below with jQuery. See the comments in the code for details:
// Below is the JSON string from the OP's link
let json = '{"data":[{"AppId":3,"AppName":"AnimojiStudio","AppSlug":"animojistudio","AppIcon":"https:\/\/img.lmdinteractive.pro\/icons\/animojistudio.png","AppUrl":"https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/animojistudio.ipa","AppVersion":"1.2.2","AppSize":"2.1"},{"AppId":2,"AppName":"Cute Cut Pro","AppSlug":"cute-cut-pro","AppIcon":"http:\/\/is2.mzstatic.com\/image\/thumb\/Purple118\/v4\/03\/70\/69\/03706968-2399-a1d8-e7c4-12897394ead9\/source\/512x512bb.jpg","AppUrl":"https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/cutecutpro.ipa","AppVersion":"","AppSize":""}]}';
// Parse the JSON string into a JS object
json = JSON.parse(json);
let html = "";
// Loop over the object and append a list item for each AppName property.
$.each(json.data, function (index, item) {
html += "<li>" + item.AppName + "</li>";
});
// Append the list to the div.
$("#container").append(html);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<div id="container"></div>

Using forEach loop and append. Inserting li inside a p tag is not a good idea even though it works. Convert the p into a ul/ol
var data = {
"data": [{
"AppId": 3,
"AppName": "AnimojiStudio",
"AppSlug": "animojistudio",
"AppIcon": "https:\/\/img.lmdinteractive.pro\/icons\/animojistudio.png",
"AppUrl": "https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/animojistudio.ipa",
"AppVersion": "1.2.2",
"AppSize": "2.1"
}, {
"AppId": 2,
"AppName": "Cute Cut Pro",
"AppSlug": "cute-cut-pro",
"AppIcon": "http:\/\/is2.mzstatic.com\/image\/thumb\/Purple118\/v4\/03\/70\/69\/03706968-2399-a1d8-e7c4-12897394ead9\/source\/512x512bb.jpg",
"AppUrl": "https:\/\/ipa.lmdinteractive.pro\/ipa\/appstore\/cutecutpro.ipa",
"AppVersion": "",
"AppSize": ""
}]
}
data.data.forEach(e =>$('#test').append('<li>' + e.AppName + '</li>' + "<br>"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="test"></ul>

You can use map() since you have an array inside myObj. What you want to do is returning a li with AppName value
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
var ul = document.getElementById("myUl");
var li = document.createElement('li');
var data = myObj.data;
data.map(app => {
li.textContent = app.AppName;
ul.appendChild(li);
})
}
};
xmlhttp.open("GET", "json.json", true);
xmlhttp.send();

You have your object, and it is parsed so let's concentrate on doing something with that object:
var myObj = {
"data": [{
"AppId": 1,
"AppName": "AppName1",
"AppSize": "2.1"
}, {
"AppId": 2,
"AppName": "AppName2",
"AppSize": ""
}]
};
Now we have that, let's use it in different ways. myObj contains an array called data here. That array is an array of JavaScript objects, each with properties like "AppId", "AppName" etc. which we can access either directly or through an index. So, let's put up some examples of how to do that. Comments in the code
var myObj = {
"data": [{
"AppId": 1,
"AppName": "AppName1",
"AppSize": "2.1"
}, {
"AppId": 2,
"AppName": "AppName2",
"AppSize": ""
}]
};
// Here I create a Bootstrap tab and contents
// call to create a new element on the DOM
function additem(item) {
let lt = $('#list-tab');
let ltc = $('#debug-tabContent');
let thing = item.name;
let thingId = "list-" + thing;
let thingTabId = thingId + "-list";
let ttab = $('<a />')
.addClass('list-group-item list-group-item-action')
.data('toggle', "list")
.prop("id", thingTabId)
.attr('role', 'tab')
.prop('href', '#' + thingId)
.html(item.name);
ttab.appendTo(lt);
let lc = $('<div />')
.addClass('tab-pane fade')
.prop("id", thingId)
.attr('role', 'tabpanel')
.text(JSON.stringify(item.obj));
// .text("test");
lc.appendTo(ltc);
}
// * cheat, put the objects in a bootstrap tab content list
additem({
name: "myObj",
obj: myObj
});
additem({
name: "myObjW",
obj: window["myObj"]
});
additem({
name: "data",
obj: myObj.data
});
additem({
name: "data0",
obj: myObj.data[0]
});
additem({
name: "AppName",
obj: myObj.data[0].AppName
});
// pure JS walk
// Here I create a LI list as a Bootstrap list group
let len = myObj.data.length;
let myP = document.getElementById("test");
let myReg = document.getElementById("mylist-reg");
let newUl = document.createElement("ul");
newUl.classList.add('list-group');
newUl.classList.add('list-group-primary');
for (var i = 0; i < len; i++) {
let newLi = document.createElement("li");
let newContent = document.createTextNode(myObj.data[i].AppName);
newLi.appendChild(newContent);
newLi.setAttribute("id", "app-" + myObj.data[i].AppId); //has to be unique
newLi.setAttribute("class", "list-group-item");
newUl.appendChild(newLi);
}
// put the list after the paragraph
document.body.insertBefore(newUl, myP);
let myLast = document.getElementById("app-2");
myLast.classList.add("active");
//activate the bootstrap tab clicks
$('#list-tab').on('click', 'a', function(e) {
e.preventDefault();
$(this).tab('show');
});
// just do it as strings
let html = "";
for (var i = 0; i < len; i++) {
let textel = "<li id='app-js-" + myObj.data[i].AppId + "'>" + myObj.data[i].AppName + "</li>";
html = html + textel;
}
myReg.innerHTML = html;
// jQuery, similar to prior
$.each(myObj.data, function(index, el) {
let textel = "<li id='app-jq-" + el.AppId + "'>" + index + ":" + el.AppName + "</li>";
$('#mylist-jq').append(textel);
});
// jQuery, similar to prior
$.each(myObj.data, function(index, el) {
let elid = 'app-jq2-' + el.AppId;
$("<li />").prop("id", elid).text(el.AppName)
.appendTo('#mylist-jq2');
});
.list-group-item {
border: 1px lime solid
}
.list-item-last {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" />
<ul id="mylist-reg"></ul>
<ul id="mylist-jq"></ul>
<ul id="mylist-jq2"></ul>
<p id="test" class="row">put stuff after here</p>
<div class="row">
<div class="col-4">
<div class="list-group" id="list-tab" role="tablist">
</div>
</div>
<div class="col-8">
<div class="tab-content" id="debug-tabContent">
<div class="tab-pane fade show active" id="list-home" role="tabpanel" aria-labelledby="list-home-list">Click a tab to see one.</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/js/bootstrap.bundle.min.js"></script>

Related

How to create a <ul> based on an array number

I am trying to make a GitHub profile searcher and what i'm trying to do is:
Get the user Avatar
Get the user Name
Get the user Repositories
I'm having troubles with the last one.
What i can't figure out is how to create a UL based in the user repos quantity.
What i have HTML:
<!DOCTYPE html>
<html>
<head>
<title>Github Profile Searcher</title>
<link rel="stylesheet" href="github-profile.css" />
</head>
<body>
<div id="username-input" class="username-input">
Username:
<input class="username-input-text" type="text" />
</div>
<div id="github-profile" class="github-profile">
<div class="github-profile-avatar">
<span class="github-profile-username">mmckalan</span>
</div>
<div class="github-profile-name">
Alan Mac Cormack
</div>
<div class="github-profile-location">
Napoli,NA
</div>
<div class="github-profile-stats">
<div class="github-profile-stat">
<i class="icon github-icon-repo" /></i>
<span id = "github-profile-repo-count" class="github-profile-repo-count">50</span>
</div>
<div class="github-profile-stat">
<i class="icon github-icon-gist" /></i>
<span class="github-profile-gist-count">12</span>
</div>
</div>
</div>
<script src="github-profile.js"></script>
</body>
JS:
var usernameInput = document.querySelector('#username-input .username-input-text');
var emptyUser = {
login: "",
name: "",
location: "",
public_repos: "",
public_gists: "",
avatar_url: "notfound.png"
};
usernameInput.addEventListener('change', function(event){
var ghReq = new XMLHttpRequest();
ghReq.addEventListener("load", updateProfileBadge);
ghReq.open("GET", "https://api.github.com/users/" + usernameInput.value);
ghReq.send();
});
function updateProfileBadge() {
var response = JSON.parse(this.reponseText);
if (response.message === "Not Found") {
updateDomWithUser(emptyUser);
} else {
updateDomWithUser(response);
}
}
function updateDomWithUser(user) {
var profile = document.getElementById('github-profile');
profile.querySelector('.github-profile-username').innerText = user.login;
profile.querySelector('.github-profile-name').innerText = user.name;
profile.querySelector('.github-profile-location').innerText = user.location;
profile.querySelector('.github-profile-repo-count').innerText =
user.public_repos;
profile.querySelector('.github-profile-gist-count').innerText =
user.public_gists;
profile.querySelector('.github-profile-avatar')
.style.backgroundImage = "url(" + user.avatar_url + ")";
}
updateDomWithUser(emptyUser);
var quantity = document.getElementById('github-profile-repo-count');
var ul = document.createElement("ul");
document.body.appendChild(ul);
What i'm trying to do is something like this:
The quantity of LI is based on the number given by user.public_repos
But it has to fit to the user repos quantity, so i don't know how to solve it.
Could u please give me a hand?
As far as I know, call to "https://api.github.com/users/NAME" would give you only the number of public respos, not names or stars. For that, you need to call "https://api.github.com/users/NAME/repos" - it may be chained after the first call.
Still, creating X list elements without data is quite easy:
var ul = document.createElement("ul");
document.body.appendChild(ul);
for (var i = 0; i < user.public_repos; i++) {
var li = document.createElement("li");
li.textContent = 'example text';
ul.appendChild(li)
}
Or, if you'll get the repos data itself, in form of array:
var ul = document.createElement("ul");
document.body.appendChild(ul);
repos.forEach((repo)=>{
var li = document.createElement("li");
li.textContent = repo.name;
ul.appendChild(li)
})
Another thing - it's better to write
public_repos: 0,
than empty string.
To create a list of repos, you just have to loop through the JSON data returned by /users/{my_user}/repos. In your case, you need two Ajax calls:
The first one gives you information about the user
The second one gives you information about the user repos
Here is a minimal working example with my repositories:
function get(endpoint, callback) {
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200) {
var data = JSON.parse(this.responseText);
callback(data);
} else {
console.log(this.status, this.statusText);
}
}
};
req.open('GET', 'https://api.github.com' + endpoint, true);
req.send(null);
}
function handleUser(data) {
var html = '';
html += '<li>' + data.login + '</li>';
html += '<li>' + data.name + '</li>';
document.querySelector('#user > ul').innerHTML = html;
get('/users/Badacadabra/repos', handleUserRepos);
}
function handleUserRepos(data) {
var html = '';
for (var i = 0; i < data.length; i++) {
html += '<li>' + data[i].name + '</li>';
}
document.querySelector('#repos > ul').innerHTML = html;
}
get('/users/Badacadabra', handleUser);
<div id="user">
<ul></ul>
</div>
<hr>
<div id="repos">
<ul></ul>
</div>

Create search list based on data from array

I have an array that should be used to create a list of search engines next to a search field.
I have this script which is working. However, it generates a select box of options - you enter a search phrase, select engine, and then get a result. However, since I have to change the markup to be using Bootstrap, I need to change the select box to an unordered list, like this:
<ul class="dropdown-menu">
<li class="selected">Select</li>
<li>Google</li>
<li>Nyheder</li>
<li>Studier</li>
</ul>
If I try to change the select into <ul id="global_search_filter" class="search_filter"></ul> and var option = jQuery(document.createElement("option")); to var option = jQuery(document.createElement("li"));the scripts breaks.
How can I achieve the same functionality but change the markup from a select box to an unordered list with list options?
I have created a fiddle here.
Maybe someone can point me in the right direction on how to solve this.
el = document.getElementById("localdomain");
el.value = window.location.hostname;
if (!window.searchEngines) {
window.searchEngines = [{
"url": "https://www.google.com",
"label": "Google",
"querykey": "q",
"id": "allWeb"
}, {
"url": "https://www.bing.com",
"label": "Bing",
"querykey": "q",
"id": "bing",
"param": {
"doctype": "",
"path": "",
"cms_mode": ""
}
}, {
"url": "https://www.yahoo.com",
"label": "Yahoo",
"querykey": "q",
"id": "yahoo",
"param": {
"gcse": "014167723083474301078:sxgnobjpld4"
}
}];
}
window.searchCallbacks = [];
jQuery(function() {
var stripPath = function(path) {
return path === "/" ? path : path.replace(/\/$/, "");
};
var isEngineCurrent = function(engine) {
if (stripPath(engine.url) !== stripPath(document.location.origin + document.location.pathname)) {
return false;
}
if (engine.param) {
for (var key in engine.param) {
if (getUrlParameter(key) !== engine.param[key]) {
return false;
}
}
}
return true;
};
var forms = jQuery("form.search_form");
forms.each(function() {
var form = jQuery(this);
var field = form.find("input.search_query");
var filter = form.find(".search_filter");
var resetForm = form.hasClass("search_reset");
if (window.searchEngines) {
for (var i = 0; i < window.searchEngines.length; i++) {
var engine = window.searchEngines[i];
var option = jQuery(document.createElement("option"));
option.text(engine.label);
option.val(i);
if (!resetForm && isEngineCurrent(engine)) {
option.attr("selected", "selected");
field.val(getUrlParameter(engine.querykey));
}
filter.append(option);
}
form.submit(function(event) {
var chosenEngine = window.searchEngines[filter.val()];
form.attr("action", chosenEngine.url);
form.attr("method", chosenEngine.method || "GET");
field.attr("name", chosenEngine.querykey);
if (chosenEngine.param) {
for (var paramName in chosenEngine.param) {
var input = jQuery(document.createElement("input"));
input.attr("type", "hidden");
input.attr("name", paramName);
input.val(chosenEngine.param[paramName]);
form.append(input);
}
}
for (var i = 0; i < window.searchCallbacks.length; i++) {
var callback = window.searchCallbacks[i];
if (jQuery.isFunction(callback)) {
callback(chosenEngine, this);
}
}
});
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="global_search_form" class="search_form search_reset" target="_blank">
<input type="text" id="global_search_query" class="search_query" placeholder="Search where...?">
<input id="localdomain" name="localdomain" type="hidden" value=" + window.location.hostname + ">
<select id="global_search_filter" class="search_filter"></select>
<button name="sa" id="submit-button" type="submit">Search</button>
</form>
Working Jsfiddle.
Here is a modified version of your code(unfortunately you can't submit a form on Stack Overflow, but you can test the jsfiddle above). Will update imediatelly with explications:
UPDATE:
Ok, so let's see what we have done here:
First we replace the select with an ul container
We append li elements to the ul parent
We add the data-selected custom attribute on every li element with empty value except the first one which we add the selected value.
We add the data-value attribute to the li element to replicate the value like when we have a select option value.
On click of a dynamically added li element we bind the click event dinamically using event delegation to add the selected attribute value.
On click of the li element we also add the selected value name to the Bootstrap button.
el = document.getElementById("localdomain");
el.value = window.location.hostname;
if (!window.searchEngines) {
window.searchEngines = [{
"url": "https://www.google.com",
"label": "Google",
"querykey": "q",
"id": "allWeb"
}, {
"url": "https://www.bing.com",
"label": "Bing",
"querykey": "q",
"id": "bing",
"param": {
"doctype": "",
"path": "",
"cms_mode": ""
}
}, {
"url": "https://www.yahoo.com",
"label": "Yahoo",
"querykey": "q",
"id": "yahoo",
"param": {
"gcse": "014167723083474301078:sxgnobjpld4"
}
}];
}
window.searchCallbacks = [];
jQuery(function() {
var stripPath = function(path) {
return path === "/" ? path : path.replace(/\/$/, "");
};
var isEngineCurrent = function(engine) {
if (stripPath(engine.url) !== stripPath(document.location.origin + document.location.pathname)) {
return false;
}
if (engine.param) {
for (var key in engine.param) {
if (getUrlParameter(key) !== engine.param[key]) {
return false;
}
}
}
return true;
};
$(document).on('click', 'li', function() {
$('li[data-selected="selected"]').attr('data-selected', '');
$(this).attr('data-selected', 'selected');
$("#menu").text($(this).text());
$("#menu").val($(this).text());
})
var forms = jQuery("form.search_form");
forms.each(function() {
var form = jQuery(this);
var field = form.find("input.search_query");
var filter = form.find(".dropdown-menu");
var resetForm = form.hasClass("search_reset");
if (window.searchEngines) {
for (var i = 0; i < window.searchEngines.length; i++) {
var engine = window.searchEngines[i];
var option = jQuery(document.createElement("li"));
option.text(engine.label);
option.attr('data-value', i);
if (i == 0) {
option.attr('data-selected', 'selected');
} else {
option.attr('data-selected', '');
}
option.attr('role', 'presentation');
if (!resetForm && isEngineCurrent(engine)) {
option.attr("selected", "selected");
field.val(getUrlParameter(engine.querykey));
}
filter.append(option);
}
form.submit(function(event) {
var chosenEngine = window.searchEngines[$('li[data-selected="selected"]').data('value')];
console.log(chosenEngine);
form.attr("action", chosenEngine.url);
form.attr("method", chosenEngine.method || "GET");
field.attr("name", chosenEngine.querykey);
if (chosenEngine.param) {
for (var paramName in chosenEngine.param) {
var input = jQuery(document.createElement("input"));
input.attr("type", "hidden");
input.attr("name", paramName);
input.val(chosenEngine.param[paramName]);
form.append(input);
}
}
for (var i = 0; i < window.searchCallbacks.length; i++) {
var callback = window.searchCallbacks[i];
if (jQuery.isFunction(callback)) {
callback(chosenEngine, this);
}
}
});
}
});
});
li[data-selected="selected"] {
color: #F00;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<form id="global_search_form" class="search_form search_reset" target="_blank">
<input type="text" id="global_search_query" class="search_query" placeholder="Search where...?">
<input id="localdomain" name="localdomain" type="hidden" value=" + window.location.hostname +">
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="menu" data-toggle="dropdown">Choose option
<span class="caret"></span></button>
<ul class="dropdown-menu" role="menu" aria-labelledby="menu">
</ul>
</div>
<button name="sa" id="submit-button" type="submit">Search</button>
</form>

generate html of inifnite depth menu without recursion

I need to create html for treeview from array of unspecified number of nodes.
Here is an example
var array = [
{
Description: "G",
Id: 1,
guid: "c8e63b35",
parent: null,
Children: [
{
Description: "Z",
Id: 9,
guid: "b1113b35",
parent: "c8e63b35",
Children: [
{
Description: "F",
Id: 3,
guid: "d2cc2233",
parent: "b1113b35",
}
]
},
]
},
{
Description: "L",
Id: 2,
guid: "a24a3b1a",
parent: null,
Children: [
{
Description: "K",
Id: 4,
guid: "cd3b11caa",
parent: "a24a3b1a",
}
}
]
the result should be
<ul>
<li id="1" data-guid="c8e63b35">G
<ul>
<li id="9" data-guid="b1113b35">Z
<ul>
<li id="3" data-guid="d2cc2233">F
</li>
</ul>
</li>
</ul>
</li>
<li id="2" data-guid="a24a3b1a">L
<ul>
<li id="4" data-guid="cd3b11caa">K
</li>
</ul>
</li>
</ul>
I wrote recursion function which generate html correctly in this example but in other cases it works perfectly to 197 depth only. If nested nodes are more than 197 it thrown an exception
"The maximum call stack size"
Is there a way to do this without using recursive functions in JavaScript?
EDIT: Here is my recursion function
var _generateHTML = function (array, html) {
for (var i = 0; i < array.length; i++) {
html += "<li id=\"" + array[i].Id + "\" data-guid=\"" + array[i].guid + "\">" + array[i].Description +
"<ul>" + _generateHTML(array[i].Children, "") + "</ul>" +
"</li>";
}
return html;
}
I cannot use external libraries because this is for my work. I created this tree using recursive functions earlier. I am wondering if this is possible thats all.
This does the trick (edit: also does indentation):
function indent (num) {
var INDENT_SIZE = 4
return new Array(INDENT_SIZE * num + 1).join(" ");
}
function ulli(input) {
var CLOSE_IT = ['JUST PLEASE DO IT']
var queue = []
var output = ""
var depth = 0;
queue = queue.concat(input)
output += "<ul>\n"
depth++
while (queue.length > 0) {
var node = queue.shift()
if (node == CLOSE_IT) {
depth--
output += indent(depth)
output += "</ul></li>\n"
continue
}
output += indent(depth)
output += '<li id="' + node.Id + '" data-guid="' + node.guid + '">' + node.Description;
if (node.Children) {
depth++
output += "<ul>\n"
newQueue = [].concat(node.Children)
newQueue.push(CLOSE_IT)
queue = newQueue.concat(queue)
} else {
output += "</li>\n"
}
}
output += "</ul>"
return output
}
Build a queue and add your root elements in it, do a while on the queue and add every child to queue. For putting elements in the correct position, u need to find their parent in dom and then add them to it.
just for the sake of completeness i'm going to provide my solution aswell.
i just want you to know that you can do DOM manipulation to achieve this.
except one small thing that i'm going to try to optimize i like the solution of #franciscod alot.
if my guess is correct i'll just edit his answer.
even though this might not be the fastest solution, this way you are also able to register events to each node right away.
example of it running: http://codepen.io/GottZ/pen/jPKpaP
this includes your raw input from this question: Converting flat structure to hierarchical
as mentioned in this comment: generate html of inifnite depth menu without recursion
in my opinion you should not use an id for every element but thats up to you to decide.
code:
var content = document.getElementById('content');
var flatArray = [
{
Description: 'G',
Id: 1,
guid: 'c8e63b35',
parent: null
},
{
Description: 'Z',
Id: 9,
guid: 'b1113b35',
parent: 'c8e63b35'
},
{
Description: 'F',
Id: 3,
guid: 'd2cc2233',
parent: 'b1113b35'
},
{
Description: 'L',
Id: 2,
guid: 'a24a3b1a',
parent: null
},
{
Description: 'K',
Id: 4,
guid: 'cd3b11caa',
parent: 'a24a3b1a'
}
];
var container = document.createElement('ul');
var allNodes = {};
flatArray.forEach(function (v) {
var element = document.createElement('li');
allNodes[v.guid] = {
element: element
};
element.setAttribute('id', v.Id);
element.setAttribute('data-guid', v.guid);
element.appendChild(document.createTextNode(v.Description));
if (!v.parent) {
container.appendChild(element);
return;
}
var p = allNodes[v.parent];
if (!p.ul) {
p.ul = p.element.appendChild(document.createElement('ul'));
}
p.ul.appendChild(element);
});
content.appendChild(container);

How can I merge an Array with an object in javascript

I'm having an array of object
var todos= [
{
id: 1,
name: test,
description: test
}
]
How can I insert an object with properties stored in different variable say
var newTodos={id:2,name:test2,description:test2,purpose:NA}
so that the final arrray looks like
var todos=
[
{
id: 1,
name: test,
description: test
},
id: 2,
name: test2,
description: test2,
purpose: NA
]
var todos= [
{
id: 1,
name: test,
description: test
}
]
var newTodos={id:2,name:test2,description:test2,purpose:NA};
todos.push(newTodos);
The answer you accepted is the right answer to the wrong question.
If you really want to add the properties of newTodos (which is misnamed; it is just a single todo) then you can do what the answer says, or more easily, just do
$.extend (todos, newTodos);
_.extend (todos, newTodos);
Object.assign(todos, newTodos);
or use your other favorite property merging utility.
However, I cannot imagine what you are going to usefully do with such a mutant object, which is an array with a single element which is a todo, and now is sort of a todo itself with the todo properties directly on it.
I'm guessing that what you want to do is add another todo to your array of todos, in which case as others have suggested you can just push it.
todos.push(newTodos)
If you actually mean newTodos to be an array of todos, as its name suggests, in other words, if its format is actually
var newTodos = [ {id:2,name:test2,description:test2,purpose:NA}, ... ];
Then to add it to todos you would concatenate:
todos = todos.concat(newTodos);
This is how you do it:
for (var index in newTodos) {
todos[index] = newTodos[index];
}
You can check the values of your array like this:
for (var index in todos) {
console.log(index + ": " + todos[index]);
}
EDIT: In conform with the asked fiddle, I add the fiddle and code:
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title> - jsFiddle demo</title>
<script type="text/javascript" src="/js/lib/dummy.js"></script>
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<style type="text/css">
</style>
<script type="text/javascript">//<![CDATA[
var VanillaRunOnDomReady = function() {
var todos= [
{
id: 1,
name: 'test',
description: 'test'
}
];
var newTodos={id:2,name:'test2',description:'test2',purpose:'NA'};
for (var index in newTodos) {
todos[index] = newTodos[index];
}
var output = "";
for (var index in todos) {
if (typeof todos[index] === "object") {
output += index + ": {";
var first = true;
for (var innerIndex in todos[index]) {
if (!first) {
output += ", ";
} else {
first = false;
}
output += innerIndex + ": " + todos[index][innerIndex];
}
output += "}<br>";
} else {
output += index + ": " + todos[index] + "<br>";
}
}
document.getElementById("output").innerHTML = output;
}
var alreadyrunflag = 0;
if (document.addEventListener)
document.addEventListener("DOMContentLoaded", function(){
alreadyrunflag=1;
VanillaRunOnDomReady();
}, false);
else if (document.all && !window.opera) {
document.write('<script type="text/javascript" id="contentloadtag" defer="defer" src="javascript:void(0)"><\/script>');
var contentloadtag = document.getElementById("contentloadtag")
contentloadtag.onreadystatechange=function(){
if (this.readyState=="complete"){
alreadyrunflag=1;
VanillaRunOnDomReady();
}
}
}
window.onload = function(){
setTimeout("if (!alreadyrunflag){VanillaRunOnDomReady}", 0);
}//]]>
</script>
</head>
<body>
<div id="output">a</div>
</body></html>

Sort JSON objects and append to html using javascript/JQM

First time using JSON and total beginner at javascript / JQM
I am trying to read a JSON file, sort it by country name ie title and display in a listview. I am not sure if I am overcomplicating things by trying to use a two dimensional array to sort. Any help, greatly appreciated.
js
<script type="text/javascript">
function ajax_get_json(){
var hr = new XMLHttpRequest();
hr.open("GET", "european_countries.json", true);
hr.setRequestHeader("Content-type", "application/json", true);
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var data = JSON.parse (hr.responseText);
var results = document.getElementById("results");
var country, flag, population, avg_growth, date;
for (var obj in data){
var countries = [[]];
var i = 0;
title = data[obj].title;
flag = data[obj].flag;
population = data[obj].population;
avg_growth = data[obj].avg_annual_growth;
date = data[obj].date;
countries[i][0] = title;
countries[i][1] = flag;
countries[i][2] = population;
countries[i][3] = avg_growth;
countries[i][4] = date;
i++;
}
countries.sort();
var listHTML = "";
for (i=0; i < countries.length; i++) {
for (var details in countries[i]) {
listHTML += '<li><a href="#' + countries[i][0] + '</a></li>';
}
}
$("#countryList").empty().append(listHTML).listview("refresh");
}
}
hr.send(null);
// display message while data loading
// could include animated gif or image here
results.innerHTML = "requesting...";
}
</script>
html
<body>
<div id="results"></div>
<div data-role="page" id="home">
<div data-role="header">
<h2>European Countries</h2>
</div>
<div role="main">
<div id="test"></div>
<ul id="countryList" data-role="listview" data-autodividers="true" data-filter="true" data-inset="true">
<li></li>
</ul>
</div>
<div data-role="footer">
</div>
</div><!-- page -->
<script type="text/javascript">
ajax_get_json();
</script>
</body>
json
{
"c1":{
"title":"Russia",
"flag":"flags/flags/Russia.png",
"population":"144,031,000",
"avg_annual_growth":"250,000",
"date":"January 1, 2015"
},
"c2":{
"title":"Germany",
"flag":"flags/Germany.png",
"population":"81,172,000",
"avg_annual_growth":"271,000",
"date":"December 31, 2013"
},
"c3":{
"title":"Turkey",
"flag":"flags/flags/Turkey.png",
"population":"78,214,000",
"avg_annual_growth":"1,035,000",
"date":"December 31, 2014"
}, ...etc
You can convert your JSON object to a single array of country objects
[
{
title:"Russia",
flag:"flags/flags/Russia.png",
population:"144,031,000",
avg_annual_growth:"250,000",
date:"January 1, 2015"
},...
]
Create a sort comparison function that compares the title field of objects in the array (Found HERE):
function compare(a,b) {
if (a.title < b.title)
return -1;
if (a.title > b.title)
return 1;
return 0;
}
So your code would end up something like this:
var countries = [];
for (var obj in data){
countries.push({
title: data[obj].title,
flag: data[obj].flag,
population: data[obj].population,
avg_annual_growth: data[obj].avg_annual_growth,
date: data[obj].date
});
}
countries.sort(compare);
var listHTML = "";
for (var i=0; i < countries.length; i++) {
listHTML += '<li>' + countries[i].title + '</li>';
}
$("#countryList").empty().append(listHTML).listview("refresh");
Working DEMO

Categories

Resources