Generate tree view using json - javascript

I want to generate tree view using jQuery and JSON.
My JSON(single folder):
[{"id":"076ac97d","path":"\/test\/undefined","name":"undefined","parentDirName":"test","parentDirId":"70b77ddd-6c15"}, .... ]
When folder is in root, parentDirId key has empty value: "", if is in catalog, has a parent ID.
I want to generate ul li list tree.
Do you have an idea how to iterate in this JSON and append ul li list to html?
I have an AJAX:
$.ajax({
type: "GET",
url: ajaxUrl,
dataType: "json",
contentType: "application/json",
success: function(response){
//code
}
How to generate dir tree? Firstly append dirs to dirs with parentID.

You could use the function below. It first creates a new object structure keyed by id, which allows quick lookup of the parent of each node. At the same time it creates an LI element for each of them, together with an empty UL element. Finally all these LI and UL elements are linked together according to the parent-child relationship:
function populateUL($ul, data) {
// Register the given UL element as the root in a new data structure
var hash = {
"": { $ul: $ul }
};
// Key the objects by their id, and create individual LI elements for them,
// and an empty UL container for their potential child elements
data.forEach(function (o) {
var $ul = $("<ul>");
hash[o.id] = {
$ul: $ul,
$li: $("<li>").text(o.name).append($ul)
};
});
// Append each LI element to the correct parent UL element
data.forEach(function (o) {
hash[o.parentDirId].$ul.append(hash[o.id].$li);
});
}
// Sample response object
var response = [{
"id":"70b77ddd-6c15",
"path":"/test",
"name":"test",
"parentDirName":"",
"parentDirId":""
}, {
"id":"076ac97d",
"path":"/test/chess",
"name":"chess",
"parentDirName":"test",
"parentDirId":"70b77ddd-6c15"
}, {
"id":"076ac97e",
"path":"/test/bingo",
"name":"bingo",
"parentDirName":"test",
"parentDirId":"70b77ddd-6c15"
}, {
"id":"076ac97f",
"path":"/test/chess/major pieces",
"name":"major pieces",
"parentDirName":"chess",
"parentDirId":"076ac97d"
}, {
"id":"076ac97g",
"path":"/test/chess/major pieces/rook",
"name":"rook",
"parentDirName":"major pieces",
"parentDirId":"076ac97f"
}, {
"id":"076ac97h",
"path":"/test/chess/major pieces/queen",
"name":"queen",
"parentDirName":"major pieces",
"parentDirId":"076ac97f"
}, {
"id":"076b0000",
"path":"/test/chess/minor pieces",
"name":"minor pieces",
"parentDirName":"chess",
"parentDirId":"076ac97d"
}, {
"id":"076b0001",
"path":"/test/chess/minor pieces/knight",
"name":"knight",
"parentDirName":"minor pieces",
"parentDirId":"076b0000"
}, {
"id":"076b0002",
"path":"/test/chess/minor pieces/bishop",
"name":"bishop",
"parentDirName":"minor pieces",
"parentDirId":"076b0000"
}];
// Inject response data into document
populateUL($("#root"), response);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="root"></ul>
For this to work, the root element must be referenced by an empty string for parentDirId.
Note that the properties path and parentDirName are not used in this algorithm, since they contain information that is redundant.

I'm guessing you mean something like this
function listItem(obj) {
var html = "<ul>"
jQuery.each(obj, function(key, value) {
html += "<li>" + key + ':'
if (typeof value !== "object")
html += value
else
html += listItem(value)
html += "</li>"
})
return html + "</ul>"
}
var obj = {
"id": "076ac97d",
"rawr": {
"mew": 2
},
"path": "\/test\/",
"name ": "undefined",
"parentDirName ": "test",
"parentDirId ": "70 b77ddd "
};
document.write(listItem(obj));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

Append key value pair in separate tags in HTML using Jquery

I have a json object(stored in a separate file) as follows -
"albums":{
"The Wall" : "1979",
"Pulse" : "1995",
"Meddle" : "1971",
"Animals" : "1977"
}
I want this to be dynamically appended in my DOM as below -
<div>
<p>Key on index i<p>
<p>Value on index i<p>
</div>
The entire div structure should render dynamically as many times as there are entries in the JSON ( in this case 4 times ).
$.getJSON("albums.json",
function (data) {
$.each(data , function (i) {
//append logic here
})
How to achieve this?
Here is a non-jQuery answer
const json = {
"The Wall": "1979",
"Pulse": "1995",
"Meddle": "1971",
"Animals": "1977",
};
for (const key in json) {
//modify element to append elements
document.body.innerHTML += `<div><p>${key}</p><p>${json[key]}</p></div>`;
}
<!DOCTYPE html>
<body>
</body>
Let's separate our concerns. First of all, you need a function with the template:
function myTemplate(key, value) {
return `
<div>
<p>${key}</p>
<p>${value}</p>
</div>
`;
}
So far, so good. Now, let's implement a cycle function:
function myBigTemplate(albums) {
var output = "";
for (let albumKey in albums) output += myTemplate(albumKey, albums[albumKey]);
return output;
}
And then you can put this into a tag, like:
myWrapper.innerHTML = myBigTemplate({"The Wall" : "1979","Pulse" : "1995","Meddle" : "1971","Animals" : "1977"});
The $.each callback function receives the key and value as parameters. Just append each <p> to the DIV with the results.
$.each(data, function(key, value) {
$("#outputdiv").append("<p>", { text: key });
$("#outputdiv").append("<p>", { text: value });
});

Set data attribute for <li> in a loop using jquery

I have been struggling with this for a day or so now,
I am pretty new to java script and building my first gui for my final project in order to achieve my qualification.
I am trying to build a music play web app.
the part i'm stuck on is when I perform a search my jquery generates a new ul element with li lising the song titles.
What im trying to do is to get the li to hold a data attribute that is unique to the song ("Mainly the file path and image path to the songs from the back end")
here is my code so far.
$("#searchButton").click(() => {
const input = $("#search").val();
const requestURL = "music/" + input.replace(/\s+/g, '%20');
$.ajax({
url: requestURL,
type: "GET",
dataType: "json",
success: (data) => {
if(data){
$('ul,li').remove();
$('<ul class="searchHeader"> </li>').text("Songs").appendTo('#songs');
$('<ul class="albumHeader"> </ul>').text("Albums").appendTo('#albums');
$('<ul class="artistHeader"> </ul>').text("Artist").appendTo('#artist');
$(data).each(function(i) {
$('<li class="results" </li>').text(data[i].songtitle).appendTo('#songsection')
})
--------//this is where i am having issues!!!!! -----
$(".results").each(function (fp){
$(this).attr("data-file", data[fp].filepath);
})
$(".results").click(() => {
loadAudio($(".results").attr("data-file"));
play();
})
var albumArray = [];
for(var i = 0; i < data.length; i++){
if(albumArray.indexOf(data[i].albumtitle) == -1){
albumArray.push(data[i].albumtitle);
}
}
for(var i = 0; i < albumArray.length; i++){
$('<li class="results" onclick=""> </li>').text(albumArray[i]).appendTo('#albumsection');
}
var artistArray = [];
for(var i = 0; i < data.length; i++){
if(artistArray.indexOf(data[i].name) == -1){
artistArray.push(data[i].name);
}
}
for(var i = 0; i < artistArray.length; i++){
$('<li class="results" onclick=""> </ul>').text(artistArray[i]).appendTo('#artistsection');
}
}
}
})
})
As you can probably guess i'm getting the same data attribute for each li,
Any help would be greatly appreciated.
Thank you
The issue at the code is
$(".results").click(() => {
loadAudio($(".results").attr("data-file"));
play();
})
within click handler, where $(".results") is the collection of all matched selectors, and .attr("data-file") gets only the first value of the selector passed to jQuery().
You can use $(this) or $(event.target) to reference the current element within $(".results") collection where the event was dispatched.
loadAudio($(this).attr("data-file"));
play();
Close tags of HTML passed to jQuery(). Multiple loops are not necessary. Use correct parameters of .each()
$(function() {
var data = [{
songtitle: 0,
filepath: 0
}, {
songtitle: 1,
filepath: 1
}];
$(data).each(function(i, value) {
$("<li>", {
"class": "results",
text: "click " + value.songtitle,
attr: {
["data-file"]: value.filepath
},
appendTo: "#songsection",
on: {click: function(event) {
console.log(event.target.dataset.file, $(this)[0].outerHTML);
/*
// use built-in `event.target.dataset` or jQuery version
loadAudio($(event.target).attr("data-file"));
play();
*/
}
}
})
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="songsection">

Javascript populating list into html select repeating list twice

I am using jquery ajax to populate a html select.
The populating actually works but the problem is that for some reason the whole list is being added twice instead of just once.
Here is the code:
myfunction: function() {
$.ajax({
url: 'the-url-here',
method: 'GET',
success: function(result) {
$.each(result.cars, function(result, value) {
if (value.active === '1'){
$('#myselect').append($('<option>').text(value.name).attr('value', value.id));
}
});
}
});
}
How can I fix this so it's only populated once and not twice?
Instead of selecting the element in the loop, which causes performance issues when the list is big, select it outside the loop, then create your list of <options> and outside the loop, append to the <select>.
(function($){$(function(){
var carsDataFetchViaAjax = [
{id: 1, active: 1, name: 'Car1'},
{id: 2, active: 1, name: 'Car2'},
{id: 3, active: 0, name: 'Car3'}
]
var $select = $('#select'),
options = [];
carsDataFetchViaAjax.map(function(car, i){
if (car.active == 1){
options.push($('<option>').val(car.id).html(car.name))
}
})
$select.append(options);
})})(jQuery)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<select id="select"></select>
myfunction is being called twice somewhere, and since an append does what it is supposed to do (appends to your list), it's working as intended :)
Check if the value is already added before trying to add it:
$.each(result.cars, function(result, value) {
if (value.active === '1' && $('#myselect option[value='+ value.id +']').length == 0) {
$('#myselect').append($('<option>').text(value.name).attr('value', value.id));
}
});

How to get all data-* attributes by Prefix

I have a tag like this:
Link
When I click this link, I have a function like this
$('#ssd').click(function (event) {
var customData;
// Code to get all the custom data in format like data-info*
});
Note, the data-info* like attributes could be any number, that means you could see 1 one of them, named data-info1, or there of them, named data-info1, data-info2, data-info3.
How would I do that, I looked up the JQuery selectors, something like Attribute Starts With Selector [name^="value"] won't work because the variation here is on name...
If I console.log($('#ssd').data()); I will get an object with extra attributes that I don't need, toggle: "popover", bs.popover: Popover
Any suggestions?
This is what I did:
dataFullList = $(this).data();
$.each(dataFullList, function (index, value) {
if (index !== "toggle" && index !== "bs.popover") {
item.name = value.split(":")[0];
item.number = value.split(":")[1];
dataIWant.push(item);
}
});
So I will get a dataIWant array without stuff I don't need.
Target all elements which data-* starts with
Custom jQuery selector selector:dataStartsWith()
Here's a custom jQuery selector that will help you to:
Given the data-foo-bar prefix , target the following elements:
data-foo-bar
data-foo-bar-baz
but not:
data-foo-someting
data-something
jQuery.extend(jQuery.expr[':'], {
"dataStartsWith" : function(el, i, p, n) {
var pCamel = p[3].replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return Object.keys(el.dataset).some(function(i, v){
return i.indexOf(pCamel) > -1;
});
}
});
// Use like:
$('p:dataStartsWith(foo-bar)').css({color:"red"});
// To get a list of data attributes:
$('p:dataStartsWith(foo-bar)').each(function(i, el){
console.log( el.dataset );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
Custom jQuery Method $().dataStartsWith()
$.fn.dataStartsWith = function(p) {
var pCamel = p.replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return this.filter(function(i, el){
return Object.keys(el.dataset).some(function(v){
return v.indexOf(pCamel) > -1;
});
});
};
$('p').dataStartsWith("foo-bar").css({color:"red"});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
This function will get the data-info attributes and put them into an array:
function getDataInfo($element, i, a) {
var index = i || 1, array = a || [],
info = $element.data('info' + index);
if(info === undefined) {
return array;
}
array['info' + index] = info;
return getDataInfo($element, index + 1, array);
}
$(function() {
console.log(getDataInfo($('#ssd')));
});
Here's an if condition to isolate the invalid keys while you loop the data. Used as a filter, you can choose to delete the keys you do not want - like this:
$('#ssd').click(function(e){
var data = $(this).data();
for(var key in data) {
//here is a condition to use only those data-info items
if(data.hasOwnProperty(key) && key.indexOf('info') === -1) {
console.log(key); //just to see which key it is
delete data[key]; //if you need to build a collection of only data-info keys
}
}
});
Alternatively, negate the if condition to include only those keys you want.
You can use Prefix Data. It is jQuery plugin. Return the value at the prefixed data store for the first element in the set of matched elements. Returned value can be an object based on the attribute values and attributes name structure.
Usage
Take any HTML tag with multi data-* attributes with the same prefix. In the example we focus on myprefix prefix.
<div id="example-tag"
data-myprefix='{"property1": "value1", "property2": {"property21": "value21"}, "property3": "value2"}'
data-myprefix-property2='{"property22": "value22"}'
data-myprefix-property2-property23="value23"
data-myprefix-property3="overwite-value3"
data-myprefix-property4='{"property41": "value41"}'
data-other="We do not read it"></div>
If you want to read data from data-myprefix and every data-myprefix-* attribute you can use .prefixData() with given prefix.
$('#example-tag').prefixData('myprefix');
The previous example returns the object:
{
property1: "value1",
property2: {
property21: "value21",
property22: "value22",
property23: "value23"
},
property3: "overwite-value3",
property4: {
property41: "value41"
}
}

How to fix automatically closing div tag in this case

I have a question about appending data to a div in my html through jquery.
This is what I have in my html file:
<div class="container">
<div class="row">
<div class="span12">
<div class="row">
<div id="errors" class="text-error"></div>
</div>
</div>
</div>
</div>
This is my javascript file:
function checkCompletion(data){
// IMPORTANT VALUES
var app_important = ["submit_description", "app_icon", "address", "email"];
var event_important = ["name", "datefrom", "dateto", "description", "email"];
$("#errors").append("<div class='span6'><div class='well'>");
// LOOPS + HEADERS
$("#errors").append("<h3>App</h3>");
doLoop(data.app, app_important);
$("#errors").append("<h3>Events</h3>");
doLoop(data.events, event_important);
}
// ar => app data array
// ar_important => important props app (array)
function doLoop(ar, ar_important) {
$.each(ar, function(value) {
$.each(ar_important, function(i) {
if(ar[value][ar_important[i]] == '') $("#errors").append("<p>" + ar_important[i]+" is missing</p>");
//else $("#errors").append("<p> :) "+ar_important[i]+"</p>");
});
});
$("#errors").append("</div></div>");
}
The data parameter is a JSON object with lots of data.
As you can see I do $("#errors").append("<div class='span6'><div class='well'>");
But the div tag automatically closes so my errors aren't in it.
Does anyone know how I can fix this and still work with append?
Niels
You don't need to build strings like this. You're already building DOM nodes in most of your code.
All you need to do is append directly to those nodes. Just fix the creation of the <div> elements, and then append to the inner most, which I think is what you're after.
function checkCompletion(data){
var app_important = ["submit_description", "app_icon", "address", "email"];
var event_important = ["name", "datefrom", "dateto", "description", "email"];
// make the outer `span6`
var span6 = $("<div class='span6'></div>")
// make the inner `well`, and append it to the span6
var well = $("<div class='well'></div>").appendTo(span6);
// do all your appends to the `well` element,
// passing it to `doLoop` so it can do the same
well.append("<h3>App</h3>");
doLoop(data.app, app_important, well);
well.append("<h3>Events</h3>");
doLoop(data.events, event_important, well);
}
function doLoop(ar, ar_important, well) {
$.each(ar, function(value) {
$.each(ar_important, function(i) {
if(ar[value][ar_important[i]] == ''){
well.append("<p>" + ar_important[i]+" is missing</p>");
}
//else{ errorAppend += "<p> :) "+ar_important[i]+"</p>";
});
});
// append the outer `span6` to `#errors`
$("#errors").append(span6);
}
There are even cleaner ways to create the elements. Here's the same code, with a better approach.
function checkCompletion(data){
var app_important = ["submit_description", "app_icon", "address", "email"];
var event_important = ["name", "datefrom", "dateto", "description", "email"];
// make the outer `span6`
var span6 = $("<div/>", {"class":"span6"})
// make the inner `well`, and append it to the span6
var well = $("<div/>", {"class":"well"}).appendTo(span6);
// do all your appends to the `well` element,
// passing it to `doLoop` so it can do the same
$("<h3/>", {text: "App"}).appendTo(well);
doLoop(data.app, app_important, well);
$("<h3/>", {text: "Events"}).appendTo(well);
doLoop(data.events, event_important, well);
}
function doLoop(ar, ar_important, well) {
$.each(ar, function(value) {
$.each(ar_important, function(i) {
if(ar[value][ar_important[i]] == ''){
$("<p/>", {text: ar_important[i]+" is missing"}).appendTo(well);
}
//else{ errorAppend += "<p> :) "+ar_important[i]+"</p>";
});
});
// append the outer `span6` to `#errors`
$("#errors").append(span6);
}

Categories

Resources