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));
});
Related
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('#',''));
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'm using a countdown script from mike giesson to create some sort of Day Deal function. The script has an onComplete function. The product data comes from a json file.
I build the product html with a getJson query. This is functioning good. The only thing I try to achieve is that when the onComplete function is fired the second object in the json file is called. After that the third etc...
Is this even possible? I have other options, like building for example 5 products and hide and show when done. I thought it would be nicer to build it this way :)
So what I have done:
jQuery
function getDaydealProducts(){
$.getJSON('url/page1.ajax', function(data){
var productsHtml = [];
$.each(data.products, function(index, product){
var productHtml =
'<div class="item">' +
... etc .... + '</div>';
productsHtml.push(productHtml);
});
productsHtml = productsHtml.join('');
$('.clock').html(productsHtml);
});
)
var myCountdown1 = new Countdown({
onComplete : countdownComplete
});
function countdownComplete(){
getDaydealProducts(); //get second product.
}
So I tried to build a function that grabs the products, then start the counter. After that a new json call needs to be done with the second object.
Is that possible? And can somebody give me some directions?
thx
I'm just learning JavaScript, and it seems there is a lot of information for folks like me about the way it processes functions asynchronously.
While I am still trying to get my head around this, I find myself struggling with some sharepoint csom because of what I am trying to do. Perhaps I am just going about this completely wrong, but as I said, just learning.
Trying to use SP CSOM to get list data like this:
getGridData() {
var gridURL = "https://mySite/ListData.svc/Projects";
var request = new Sys.Net.WebRequest();
request.set_httpVerb("GET");
request.set_url(gridURL);
request.get_headers()["Accept"] = "application/json";
request.add_completed(onCompletedProjectCallback);
request.invoke();
}
onCompletedProjectCallback(response, eventArgs) {
var getProject = eval("(" + response.get_responseData() + ")");
var buildMarkUp = '';
for (var i = 0; i < getProject.d.results.length; i++) {
buildMarkUp += "<div>" + getProject.d.results[i].ProjectName + "</div>";
}
}
This works great.
I do know about other methods such as spservices, but I like this as it seems to be faster for me and returns JSON which is preferable.
What happens when I want to use the ProjectID in the above to call another function and pass the id in order to get related values from a list.
However, I want to build the buildMarkUp string in order before it gets appended to the DOM(oh yeah jQuery btw). Something like this might be totally wrong, but it is what I was trying to do:
onCompletedProjectCallback(response, eventArgs) {
var getProject = eval("(" + response.get_responseData() + ")");
var buildMarkUp = '';
for (var i = 0; i < getProject.d.results.length; i++) {
buildMarkUp += "<div>" + getProject.d.results[i].ProjectName + "</div>";
//call nested function here so that I can go retrieve values for each ProjectID from another list
var getOtherData = getRelatedData(getProject.d.results[i].ProjectID);
}
}
getRelatedData(passedProjectID) {
// have to use the same method as the original to get more sharepoint list data
var relatedURL = "https://mySite/ListData.svc/Related$filter=ProjectID eq " + passedProjectID;
var request = new Sys.Net.WebRequest();
request.set_httpVerb("GET");
request.set_url(relatedURL);
request.get_headers()["Accept"] = "application/json";
request.add_completed(onCompletedRelatedCallback);
request.invoke();
}
This is where I am really struggling with this though.
A separate callback means it is not going back to the original function with data if I return right?
Does the original function keep processing and just fire the nested functions?
How can I control when/how/what values are returned to the original function then? Can I?
Basically what if I was trying to build a table, where each referenced project row contained data from other sharepoint lists, and I would need to control the order in which the string that I was going to append to the DOM got built?
You are correct that a function that executes a web request continues immediately and cannot return the data from that call. You need to code the callbacks to add the data they collected to a public data structure -- perhaps create an object that accumulates the data as new attributes. When you have collected all of the data, the last callback can build the HTML elements. If you are doing multiple simultaneous AJAX requests, then each callback can call a common function to see if all requests have finished. For example:
function checkLoadingComplete() {
if (loadedData.project && loadedData.relatedData && loadedData.summaryData) {
//now build the HTML elements
}
}
A separate callback means it is not going back to the original function with data if I return right?
Yes. return returns from the function executing, but does not wait for the ajax load event and its handler to get the data.
Does the original function keep processing and just fire the nested functions?
Yes. It starts a bunch of ajax requests, and gets back undefined for each of them.
How can I control when/how/what values are returned to the original function then? Can I?
You will need to use callbacks, you never will "return" the values.
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');