I have one of the most frustuating problems i have ever had with a programming language.
Im reading some xml and then trying to display on the web page. i have no problem doing that.
Here is the code of how im accomplishing this.
// File: readXML.js
var shared = [];
var sheet = new Array()
// Start function when DOM has completely loaded
$(document).ready(function(){
var bigo = new Object();
console.log("can you see me.");
var sheetJoint = new Object();
// get the sheet xml file
$.get("sheet1.xml",{},function(xml){
var attrs = [];
// this is a loop within a loop. we traverse the values in the xml to get end up with a key pair value of key: val
// in our case this works out to be A1 = 0 this is the first step to get the actual value from the sharedstring.xml
// Run the function for each row tag in the XML file
$(xml).find("row").each(function(i) {
//run the function for each c tag in the xml and get the attribute.
//this is the attribute that references the actual column.
$(this).find("c").each(function(i){
$('c',xml).each(function(i) {
v1 = $(this).attr("r");
bigo[v1] =v1;
bigo[v1]= $(this).find("v").text();
});
})});
//get the shared string elements to combine with the other
$.get("sharedStrings.xml",{},function(xml){
$('si',xml).each(function(i) {
shared.push($(this).find("t").text());
})});
});
combineObjects(bigo);//combine the the array and the object.
});
since i have two read two different xml files i have to use another function to combine them. Here is that function.
function combineObjects(obj){
myHTMLOutput = '';
myHTMLOutput += '<table width="98%" border="1" cellpadding="0" cellspacing="0">';
myHTMLOutput += '<th>A</th>';
//mydiv=document.getElementById("ContentArea")
try{
var strt="";
var tempVal;
//loop throught the obejct and get the value from the returnTheValueSegment.
for (var ind in obj){
//if you want to print something to the log then just add this.
// pretty handy when trying to discover variable values. does not see to work well inside for loops thought.
// console.log("can you see me.");
tempVal = returnTheValueOfSegment(obj[ind]);
//bring the values
obj[ind] = tempVal;
}
for (var ind in obj){
mydata = BuildStudentHTML(ind);
myHTMLOutput = myHTMLOutput + mydata;
}
myHTMLOutput += '</table>';
$("#ContentArea").append(myHTMLOutput);
}
catch(err){alert(err)};
}
my problem occurs when i'm creating the table. its basically hit or miss...
if i try it in firefox it work only if i use firebug and step through the code otherwise it doe s not show the table elements.
here is the code that is being called to make the table.
function BuildStudentHTML(column1){
// Build HTML string and return
output = '';
output += '<tr>';
output += '<td>'+ column1 +'</td>';
output += '</tr>';
return output;
}
what could i be doing wrong. do i need some sort of timer? is it that the loop is to fast and the page cant refresh. Please if someone can point me in the right direction i would be for ever grateful.
In your code, combineObjects(bigo); is called before the HTTP requests for the XML files can finish. $.get() starts a new HTTP request and then runs the success function when the request has finished loading. You could try putting combineObjects(bigo); in the success function for the last XML document, but that won't work because bigo will be undefined in that function. The solution is to create a function that creates a function. Put this before the $(document).ready() function:
function second_XML(bigo){
return function(xml){
$('si', xml).each(function (i) {
shared.push($(this).find("t").text());
});
combineObjects(bigo); //combine the the array and the object.
}
}
This allows you to pass the bigo variable to the function as an outer variable. Next, replace the code that loads the second XML document with this:
//get the shared string elements to combine with the other
$.get("sharedStrings.xml", {}, second_XML(bigo));
This will make the code wait until the second XML file has loaded before combining the two. For some reason, you already made your code wait for the first XML document to load before loading the second, so you don't have a problem there.
Related
I'm trying to insert into an html table data, retrieved with ajax
the response arrive as:
[{"email":"marc#volvo.com","id":2,"name":"volvo"},{"email":"marc#mercedes.com","id":4,"name":"mercedes"}]
that's look fine, but when I try to access it as an object, I receive undefined.
if I bring it as json type, it show the word object instead of the object content.
It should be an array of 2 object, with 3 value each, no matter what i tries i can't manage to access the value,
here's the javascript code (i don't know yet jquery) :
function getCompanies(){
var req = new XMLHttpRequest()
var url = "http://localhost:8080/CouponB/webapi/admin/company"
req.open("GET", url, true)
req.send()
req.onreadystatechange = function() {
if(req.readyState==4) {
if(req.status==200){
myStr = ""
var resp = req.response
alert(resp)
myJson = eval(resp)
alert(myJson)
for(var x in myJson){
alert("-----------"+x.name)
}
var respTarg = document.getElementById("companyTable")
resp.forEach(wtr)
respTarg.innerHTML = myStr
}
}
}
}
function wtd(d){
return "<td style=\"width: 70px; \">"+d+"</td>"
}
function wtr(){
myStr += wtd(this.id)+wtd(this.name)+wtd(this.email)
}
Have a look at Access / process (nested) objects, arrays or JSON to learn more about how to process nested data structures.
There are a couple of issue with your code:
Using eval to parse the JSON (it works, but there is a better way)
Using for...in to iterate over an array and incorrectly access array elements (x refers to the index of the element, not the element itself). (this is broken)
Using this inside wrt. forEach does not make the current element available via this. (this is broken)
Using a global variable myStr to build the HTML instead of having wrt return a string. (it works, but there is a better way)
If respTarg is a <table> then you are forgetting to create rows (<tr>). (might work, but then all cells appear in a single row)
Having said that, here is a way to build a simple table:
var resp = '[{"email":"marc#volvo.com","id":2,"name":"volvo"}, {"email":"marc#mercedes.com","id":4,"name":"mercedes"}]';
function insertCell(row, value) {
// create a new cell in the provided row
var cell = row.insertCell();
// set the inline style of the cell
cell.style = {width: '70px'};
// set the content of the cell
cell.textContent = value;
}
var table = document.getElementById('table');
// parse the JSON and for each object in the resulting array ...
JSON.parse(resp).forEach(function(obj) {
// ... create a new row ...
var row = table.insertRow();
// ... and insert the following properties as cells into the row
insertCell(row, obj.id);
insertCell(row, obj.name);
insertCell(row, obj.email);
});
<table id="table"></table>
Also, don't use alert for debugging, use console.log instead.
I'm using a API that returns JSON on request. This JSON has either names for next level URL's or a filename.
The problem is that code has to recognize which JSON is returned.
If JSON only has a names for next url levels then create url and get it.
Then recursively get a new set of names or files, recognize and do it over. It can go as menu levels deep as required. 1 to *
If it has a filename it should get it and render it as html.
(This is already solved)
Example of json
{id: 'New_url_1_level_1', id:'New_url_2_level_1', id:'New_url_3_level_1'}
//or
{id:'001200.file.ext',id:'001300.file.ext'...}
These would turn into http://my.api.call.com/New_url_1_level_1.../New_url1_level_2/...
The problem is that how to loop over URL's and to finally get to filename for example:
http://my.api.call.com/New_url_1_level_1/New_url_1_level_2/New_url_1_level_3/001300.file.ext
My current script is:
var json;
var urllevel= '/First_level';
var api = 'http://my.api.call.com';
var re = /^\d+/g; // Regex to match filename (decide if json has filenames or urls; files always start with digits or end with extension)
var loopApiUrl = new Array();
var recursion = false;
// This is the problem - how to recursively build url's based on returned data i.e. traverse a "unknown" tree
function recursePxJson(){
if (!recursion) {
loopApiUrl = [];
}
// Get JSON
$.get(api+urllevel+'/'+loopApiUrl.join('/'),function(data,status){
for (var i in data) {
if (!re.test(data[i].id)) { // {id: 'This_is_to_be_appended_to_url', id:'Another_appendable'}
recursion = true;
loopApiUrl.push(data[i].id);
recursePxJson();
}
else { // {id:'001200.file.ext',id:'001300.file.ext'}
load(api+urllevel+'/'+loopApiUrl.join('/')+'/'+data[i].id);
recursion = false;
}
}
});
//loadDBS(param);
}
// Load renderable JSON - ALREADY SOLVED
function load(param){
$.get(param, function(data, status){
json = JSON.stringify(data);
var title = data.title.split(':');
html = '<h2>'+title[0]+'</h2>';
html += '<h3>'+title[1]+'</h3>';
html += '<h5>Values:</h5>';
for (var i=0; i<data.variables.length; i++) {
html += '<b>'+data.variables[i].text+': </b>';
varlen = data.variables[i].valueTexts.length;
if (varlen > 6) {
html += '<i>'+data.variables[i].valueTexts[0]+', '+data.variables[i].valueTexts[1]+', '+data.variables[i].valueTexts[2]+' . . . '+data.variables[i].valueTexts[varlen-3]+', '+data.variables[i].valueTexts[varlen-2]+', '+data.variables[i].valueTexts[varlen-1]+'</i>'+'<b> (yhteensä '+varlen+' arvoa)</b>';
} else {
html += '<i>'+data.variables[i].valueTexts.join(',')+'</i>';
}
html += '<br/>';
}
$(html+'<br>').appendTo($('#tab2'));
});
}
EDIT: At the moment it seems like it is does each for loop before it begins another. Therefore it starts one in loop and if another is instatiated it won't be run before the fist one is done.
Main loop
Internal Loop 1
Internal Loop 2 <- Isn't this the one that should done first?
Handle your loopApiUrl variable as a parameter for your function recursePxJson().
Get rid of the useless recursion boolean.
You may find it easier to ditch jQuery and make use of a plain old XMLHTTPRequest. Your code will be slightly longer but you'll gain a better control of what your doing.
So I save my array as a variable: var arrayContents = contentData;
and my array: ['content_1', 'content_2', 'content_3', 'content_4']
So i've got my array, I then want to place it into my HTML which i've done via using text like such: $('.container').text(arrayContents);
I need to break my text up so it currently looks like:
And i'm trying to get it to look like :
How can I break my array up so each item drops onto a new line? As when I use .text I print the whole array as one not each separate item.
Use a foreach loop and add a <br> tag to go to next line:
var contentToInsert;
$.each(arrayContents,function(value){
contentToInsert += value + "<br>";
});
$('.container').html(arrayContents);
You need to use html() instead of text(), check this
var htm = '';
var arrayContents = ['content_1','content_2','content_3'];
arrayContents.forEach(function(item){
htm += item + '<br />'; // break after each item
});
$('.container').html(htm);
Actually .text() works with a string value. You passed an array, which leads the "engine" to call arrayContents.toString() to get a string from the array. As you can see there, this function separates each entry by a comma.
If you want to produce an output on one column, you have to generate HTML (as shown in this answer), or editing the div object through javascript DOM functions (fiddle) :
for (var i = 0; i < arrayContents.length; i++) {
var currentElement = document.createElement("DIV"); // "DIV" or block-type element
var currentText = document.createTextNode(arrayContents[i]);
currentElement.appendChild(currentText);
document.getElementById("container").appendChild(currentElement);
}
Be sure of what kind of HTML you want to produce.
I'm not sure how to code GAS form buttons to fire a script with dynamic values.
In this scenario, the current sheet cell value is used to Look-Up rows in an adjoining sheet and to populate a result array.
A form then presents a list of buttons containing values from one column of the result array.
Pressing a form button should fire the script postLocationData, and update the current cell and adjoining cells in the row with result array values, and closes the form. At this point, pressing a form button does not seem to do anything. Much thanks in advance for your help :)
function lookUpLocationTest(){
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getActiveCell();
var sheetLocations = ss.getSheetByName('LU_Locations');
var arrayRecords = sheetLocations.getRange(2, 3, sheetLocations.getLastRow(), 2).getValues();
var matchingLocations=[];
for (var i=0;i<arrayRecords.length;i++) {
var result = arrayRecords[i][1].indexOf(cell.getValue())
if(result !== -1) {
matchingLocations.push(arrayRecords[i]);
}
}
if(matchingLocations.length === 0){
var result = ui.alert(
'Message:',
'No Matching Location Found.',
ui.ButtonSet.OK);
return 0;
}
Logger.log(' Process - ' + matchingLocations.length + ' Locations have been found.') ; //matchingLocations is a global
// Prep Form HTML with formatted matching Locations
var HTML= '<form><div>'
for(var i=0;i<matchingLocations.length;i++){
HTML += "<div><input type='button' value='" + matchingLocations[i][1]
+ "' onclick='google.script.run.withSuccessHandler(postLocationData).processForm(this.parentNode)'/></div>";
}
var htmlOutput = HtmlService.createHtmlOutput(HTML).setSandboxMode(HtmlService.SandboxMode.IFRAME);
var result = SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Matching Locations');
return 1;
}
function postLocationData(lookUpValue) {
var location = lookUpValuesInArray (matchingLocations, 1, lookUpValue); //matchingLocations is a global
var cell = currCell;
var latLongCol = 3;
cell.setValue(location[0][1]);
cell.getRowIndex();
var sheet = cell.getSheet();
sheet.getRange(cell.getRowIndex(), latLongCol).setValue(location[0][0]);
var temp =1;
}
The function "google.script.run" will be executed on the client side but it will call a function on the serverside (your .gs file). In this case the function you will call is "processForm()" where you are sending "this.parentNode" as parameter.
In you Apps script file (gs file) you should have a function called "processForm()" you didn't post it in the example.
After this function ends, if everything went well, the function "google.script.run" will execute the function that you defined in "withSuccessHandler()". In you example you used "postLocationData".
This function will receive as parameter the results returned from the execution of processForm().
As I mentioned before google.script.run is called on the client side, therefore the function that will be executed if everything went well (the one contained in withSuccessHandler), has to be also in the client side. This means it has to be part of the script contained in the HTML.
As the way you posted the code, I would change the onclick to:
onclick='google.script.run.withSuccessHandler(someJavascriptFunction).postLocationData(this.parentNode)
withSuccessHandler is optional, if you decided to use it, then you should create a html script tag in you HTML variable having that javascript function to show an alert or something that tells the user the result of clicking the button.
You can also create an html file in the appsscript project and call it like: HtmlService.createHtmlOutputFromFile('Index').setSandboxMode(HtmlService.SandboxMode.IFRAME);
This way you can have a cleaner html file and the javascript asociated to it.
Hope this helps.
I was wondering how to add a html link to each JSON item as it is returned.
php file
//relevant code, $result contains sql query with records from a search
$records = array();
while($array = mysqli_fetch_array($result))
{
$records[] = $array;
}
echo(json_encode($records));
Output html via ajax
function responseReceived(e){
document.getElementById('response').innerHTML = e.target.responseText;
}
Response is a div tag. So I was wondering how would I add html link (to another page) to each item within the json. Because at the moment it outputs json but it's not allowing me to add html.
This is the current output, which is as expected due to me entering data via a form, I just want to add a small html link next to him.
[{"0":"1115","ID":"1115","1":"john","name":"john","2":"male","type":"male","3":"berk","country":"berk","4":"aus","region":"aus","5":"32.43","lon":"32.43","6":"32.54","lat":"32.54","7":"nothing to say","description":"nothing to say"}]
Thanks, in advance.
Where will you get the link from?
Is the returned data the link or is the returned data some text that should be formatted as a link?
If it's the second one, you need to get the link from somewhere.
What you could do is storing some sort of link/id in the database and print that out in the json so it will output something like:
[{"url": "http://example.com", "content": "This is a link!"}]
I presume that you know how to do a ajax call, so let's just continue to the formatting:
// Let's make a function
function createLinks(json){
// Let's parse the JSON first (if it's a string)
json = JSON.parse(json);
// Loop through all the elements
for(var i = 0; i < json.length; i++){
// Check if the fields exist
if(json[i].url && json[i].content){
// Creating a tag
var a = document.createElement("a");
// Let's add the values to the a tag
a.href = json[i].url;
a.textContent = json[i].content;
// ^ or innerHTML if you want to have HTML code there
// Appending to body element (just for this example)
document.body.appendChild(a);
}
}
}
I hope it helps!
This simple code adds a link to every single array item. If you want to transform it to HTML, just create the HTML string and then you can insert it with innerHTML.
var obj = JSON.parse('[{"0":"1115","ID":"1115","1":"john","name":"john","2":"male","type":"male","3":"berk","country":"berk","4":"aus","region":"aus","5":"32.43","lon":"32.43","6":"32.54","lat":"32.54","7":"nothing to say","description":"nothing to say"},{"0":"1115","ID":"1115","1":"john","name":"john","2":"male","type":"male","3":"berk","country":"berk","4":"aus","region":"aus","5":"32.43","lon":"32.43","6":"32.54","lat":"32.54","7":"nothing to say","description":"ggg"}]');
for (var i = 0; i < obj.length; i++) {
obj[i].link = 'Google';
}