So I'm just getting into some simple UI stuff, and I'm stuggling with Javascript. I managed to get a couple of for-loops to create tags and render some charts, works great.
But I then used jquery to fetch a block of JSON data from a Spring Boot REST service.
$.getJSON('api/randomData?chartCount=' + chartsToMake).done( function(data) {
// Extract list of servers from the data...
var hostList = []
$.map(data, function(row) { hostList.push(row.host); });
// Make it a unique list
var uniqueHostList = hostList.unique();
// Iterate over the unique list of servers
uniqueHostList.forEach( function(host) {
var tag = "chart" + host.replace(/\./g, "");
var hostdata = data.filter( (v,i,a) => v.host === host)
console.log("Processing Server:" + host + " with " + hostdata.length + " rows");
// Create DOM element to bind the chart to
document.getElementById("chartBlocks").innerHTML += "<div id=\"" + tag.replaceAll('#','') + "\"></div>";
// Create the Chart here
var chart = c3.generate({
bindto: "#" + tag,
data: {
json: hostdata,
keys: { value: ['lowerband'] }
}
});
});
});
This gets an array of JSON strings back, each object contains one metric for a server, all the HTML tags are inserted, but only the last chart draws up.
I added lots of console.out() stuff to try and debug this, it has the data and everything seems to be working, and the last chart looks fine, but the other 3 above it dont populate.
I've been pulling my hair out trying to work out why, please help!
PS. I created a github project here which is a simple maven/spring boot application.
https://github.com/tfindlay-au/c3demo
There is a working page called "working.html" and "index.html" which doesnt work.
FWIW - it feels like a variable scope thing or maybe a timing thing if I'm trying to generate the chart before the data is avilable or something. Not sure if that helps.
"only the last chart draws up."
document.getElementById("chartBlocks").innerHTML += "<div id=\"" + tag.replaceAll('#','') + "\"></div>";
Because that line (at first I thought it completely replaced the content but then I saw the += ) has bad side-effects for the existing content of chartblocks. Specifically it wipes out the event functionality (edit: and data) which setting up a c3.chart has attached to elements in that chart. When you then set innerHTML in chartblocks again, all that stuff is replaced by the innerHTML string, which is just a literal copy of the structure of the dom elements - wiping out any previously attached event handlers or data properties.
You instead need to append an extra div to chartblocks, which leaves the existing sibling charts in peace, and since c3 uses the d3 library you can do it like this:
d3.select("#chartBlocks").append("div").attr("id", tag.replace('#',''));
Related
I'm working within WikiPedia API, (MediaWiki) and have been doing a lot of research on how to get results/push them into an array. Using Angular, I was finally able to get a successful 'forEach' to work for this matter.
My issue now is when I try to '.append' the data (An Object) to HTML, it isn't working for me. To test, I did console.log it and it's reporting the Objects and their existence to the console log, but unsure how to really push it into HTML Formatting.
I have attached a CodePen that is forked at my current state for review. I am new to Angular, so that isn't my key focus - I'm unsure why Angular can parse objects, but it does work.
function wiki() {
$('#results').html('');
result = [];
search = $('#search').val();
$.getJSON(link + search, function(wikis) {
var tempRes = wikis.query.pages;
var page = 'http://en.wikipedia.org/?curid=';
angular.forEach(tempRes, function(v, k) {
result.push({
title: v.title,
body: v.extract,
page: page + v.pageid
})
console.log(result);
$('#results').append(result)
})
})
}
The link + search variables are established early in the code, and work successfully.
Any assistance would be perfect - Been working on this bit for awhile.
Code Pen Link
Edit:
Upon further trial-n-error, my issue was resolved by modifying the Append to reflect:
$('#results').append('<li>' + result[i].title + '<br>' + result[i].body+ '<br>' + result[i].page + '</li>')
I'm thinking that just pulling result, or result[i] wasn't enough to provide proper modification. I appreciate the off-topic replies, and advice.
In order to append HTML to an element you need to build it first. Either construct your HTML tags as a string front the objects and then append, or create the elements and then append:
var html = "";
result.each(function () {
html += buildHtmlFromObject(this);
});
$('#results').append(html);
$('#results').append('<li>' + result[i].title + '<br>' + result[i].body+ '<br>' + result[i].page + '</li>')
Was the cost that resolved my issue. I needed to append the exact calls, other-wise it was trying to access an object within an object (And since the first Object is random, I couldn't forsee it.)
I am using Sigma.js with the cypher plugin to visualise my neo4j database. After following the simple example here https://github.com/jacomyal/sigma.js/blob/master/examples/load-neo4j-cypher-query.html , it is working well. I edited the plugin so that the graph labels displayed are the names of my neo4j nodes, however I would also like to show the other node properties when clicking on the label or node.I am quite new to JavaScript so would like to know if this is possible for a beginner like me to do and if it is where is the best place for me to start.
You have to register an event on the click or hover node.
There is an example into sigmajs for event : https://github.com/jacomyal/sigma.js/blob/master/examples/events.html
This is a short code that demonstrate how to make this. Replace the alert method by what you want.
sigma.bind('overNode', function(event) {
alert(event.data.node);
});
If you just want to discover your database, take a look at tank-browser : https://www.npmjs.com/package/tank-browser
Cheers
You have to edit Cypher plugin
First: Define var let's assume we will call it "has" at the beginning of the file.
Second: You should add ul in your html and add class to it called 'popover'
Third: Add to cypherCallback method you should add inside else if (typeof sig === 'object')
sig.graph.read(graph);
sig.bind('clickNode', function(e) {
var clicknode = e.data.node;
// empty the printed list
$('.popover').empty();
has='';
// create the tlis tof prop. from returend Object
for(var keys in clicknode.neo4j_data ){
$('.popover').append(' <li>' + keys + ' = '+ clicknode.neo4j_data[keys] + '</li>');
has+= 'n.' +keys + '="'+ clicknode.neo4j_data[keys] + '"AND ';
}
$('.popover').show();
});
sig.bind('clickStage', function(e) {
$('.popover').hide();
});
I have a very large JSON object, which serves as a data source from which my page is created. Currently I am able to load the whole object, create DIVs from it and the display it. However when the JSON is very big it takes a lot of time and then suddenly the whole content is displayed. I would like to load each child separately, or display the loaded content after each node (appending).
The JSON has the following structure:
{
id:"0",
text:"",
children:[{
id:"0-0",
text:"",
children:[...]
},
{
id:"",
text:"0-1",
children:[...]
}]
}
When I load this object I call a function which creates the container based on the root node and then a recursive function which gets executed for every child.
function loadRoot(wholeJson){
var rootDiv = '<div id="frag-' + wholeJson.id + '"></div>';
return rootDiv;
}
function loadChildren(wholeJson){
rootDiv = $('#frag-' + wholeJson.id);
wholeJson.children.forEach(function(child){
loadChild(child);
});
}
function loadChild(node){
var newDiv = // create the div here..
node.children.forEach(function(child){
loadChild(child);
});
newDiv += "</div>" //close it
return newDiv;
}
This works, but as I mentioned it loads the whole content at once. How can I achieve the displaying of every child after it's created and not only at the end of script execution, please?
I had a similar problem. The reason why this happens is that javascript first processes your function in the background, and when it is all done, it's changes will be made. I do not know if its the best way to go. But setTimeout with a anonymous function worked for me. Just set the waiting time really low.
I have a codeigniter app and in one of my views, i have an ajax call to an API that returns json data. Once i get the data, I loop through it and append records to an existing table.
There are two ways to run this ajax call. One is to request "all" data, the other is to filter by location.
Both ways return data, but when Im trying to loop through the filtered data set, the ajax is failing.
Here's the code that loops through the record set:
if (JSONdata.length != 0)
{
//create a heading row and attach it to the existing table.
var heading = $('<tr id="tblheading" naming="tblheading">').appendTo($('#switchrecords'));
heading.append($('<td>').append().text('Name'));
heading.append($('<td>').append().text('Object ID'));
//loop through each JSONdata item in the array and append another row to the switchrecords table.
$.each(JSONdata, function(i, objswitch) {
console.log('objectid is:'.objswitch.id);
console.log(objswitch.id);
var row = $('<tr>').appendTo($('#switchrecords'));
row.append($('<td>').append($('<a href='+ BASEPATH + 'index.php/controller/methodname/' + objswitch.id + '>').text(objswitch.name)));
row.append($('<td>').append(objswitch.id).text(objswitch.id));
});
Here's what I've done so far:
I've made sure that both result sets have the same fields, namely "id" and "name". Mind you, the filtered data set includes more fields than the non filtered result but i don't think that should matter.
I've used console.log to dump both result sets... Here's a snippet from both. The first one is ALL and the other is filtered.
[{"name":"888-12-993-99-1","id":"1","dict_value":"compact"},{"name":"888-22-SR1-RTR-1","id":"2","dict_value":"compact"},{"name":"888-21-SR1-SW-1","id":"3","dict_value":"compact"},{"name":"888-11-SR2-SW-2","id":"4","dict_value":"compact"},....etc
[{"parent_id":"2","tag_id":"10","Location":"Building1","id":"7","name":"888-22-228-22-1","label":null,"asset_no":"1026067","objtype_id":"1503"},{"parent_id":"2","tag_id":"5","Location":"Building2","id":"6","name":"888-2-263-88-1","label":null,"asset_no":"1026068","objtype_id":"1503"}, .... etc.
As you can see from the code snippet, I've tried to add some debug information to see what's happening inside the loop. However, I'm getting the following error message on the first console.log() call:
[17:13:30.675] TypeError: "objectid is:".objswitch is undefined
I'm not really too sure how to resolve this. Any suggestions would be appreciated.
I apologize in advance if it's a silly mistake! I've been programming all day and my brain is mush! =)
Thanks in advance for the help.
Unless I'm completely off it looks like .objswitch should be + objswitch.
Try
console.log('objectid is:' + objswitch.id);
instead of
console.log('objectid is:'.objswitch.id);
Looks like your syntax is wrong for concatenation .. It should be done using a + , I see you are using a .
Instead of objswitch try using this
$.each(JSONdata, function(i) {
console.log('objectid is:' + this.id);
console.log(this.id);
var row = $('<tr>').appendTo($('#switchrecords'));
row.append($('<td>').append($('<a href='+ BASEPATH + 'index.php/switches/getswitchdetails/' + this.id + '>').text(this.name)));
row.append($('<td>').append(this.id).text(this.id));
});
Otherwise try using the variable in general
$.each(JSONdata, function(i) {
console.log('objectid is:'+ JSONdata[i].id);
console.log(JSONdata[i].id);
var row = $('<tr>').appendTo($('#switchrecords'));
row.append($('<td>').append($('<a href='+ BASEPATH + 'index.php/switches/getswitchdetails/' + JSONdata[i].id + '>').text(JSONdata[i].name)));
row.append($('<td>').append(JSONdata[i].id).text(JSONdata[i].id));
});
I've got a page that makes an ajax request and gets data back in json format.
I needed to sort this data before adding it to the DOM, so it is put into an object with the following code
function(data) {
var birthDates = {};
var uids = {};
$.each(data.users, function() {
if (!uids[this.uid]) {
uids[this.uid] = [];
uids[this.uid].push(this);
}
if (!birthDates[this.birthDate])
birthDates[this.birthDate] = [];
birthDates[this.birthDate].push(this);
});
for (var d in birthDates) {
var date = d;
$('div#holdDates').append('<ul class="dayList" id="' + date + '"><li class="date" >' + date + '</li></ul>');
$.each(birthDates[date], function() {
$('ul#' + date).append('<li class="show" id="' + this.uid + '">' + this.name + '</li>');
});
}
$('li.show').click(function() {
var getuid = $(this).attr('id');
$showArr = uids[getuid];
// now I can get the extended data about the user
this all works great when the page is loaded for the first time, however I'm running into two problems, both as a result of making a second ajax request
1) if i make the same ajax request (giving the same variables, so the same data comes back again), then the data gets added to the newly created objects (uids, and birthDates) twice, and I can't figure out how to keep that as unique
2) sometimes (and i haven't been able to debug to figure out why) i don't get any of the extended user data from uids object. (the stuff I do after the li click
Any ideas? Am i doing this efficiently?
I find it strange that you can't empty an object that you've created, but apparently everything I'm reading says that you can't.
Addition
well, after posting this, the next thing I was doing was building a dynamic tag cloud which is dependent on the returned json.
so, now I run into the same problem again. I need to tag-cloud to be new after each request. I really hope there is a way to get rid of 'legacy' data in javascript.
Thanks,
Pete
Everything declared with the var keyword inside of your function(data) will be created anew each time the function is called.
What's the symptom of your problem? Have you actually looked at the value of the uids variable in firebug and seen that items are being duplicated, or do you just see your dates/names getting doubled up on the page?
My suspicion is that this is a result of not clearing the DOM elements that you are calling .append() on before you display your results.
Try adding to the beginning of the function:
$('div#holdDates').empty();
as well as to your date display loop:
$('ul#'+date).empty();
and for good measure, at the beginning of function:
$('li.show').unbind('click');