I'm currently developing a web application for the school where I work. We have a program called FROG on one of our dedicated servers. Unfortunately this is very locked down, and you create websites using a a gui. The most coding you can do on it is HTML and javascript.
I want to be able to retrieve information from a remote server which we also own. I cant use ajax due to the cross domain restrictions. However I have come up with a work around.
I have this function call on my remote server within a file called xrequest.js:
loadNotices({[{title: 'this is a test'},{title: 'this is another test'}]});
This is simply a function call with a json object passed as an argument (The argument will ultimately be generated from data retrieved from a database).
On my other restricted server, I have this javacript:
<script type="text/javascript">
function loadNotices(data)
{
alert(data);
}
var url = "http://somedomain.com/tests/xrequest.js";
var script = document.createElement('script');
script.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(script);
</script>
<div id="notices"></div>
What I want to do is loop through each of the titles in the xrequest.js file, and display them as a list.
Im unsure how to loop through the titles.
If you need any more information, please leave a comment. Any help is appriciated.
Many thanks
Phil
To loop over the titles, you first need to remove the curly braces around your array. After, loop through the titles like below:
function loadNotices(arr) {
var title, i = 0;
for (; i < arr.length; i++) {
title = arr[i].title;
}
}
Also, look into changing:
document.getElementsByTagName('head')[0].appendChild(script);
to
document.head.appendChild(script);
Your implementation look like JSONP call. With Jquery you can make it easy
$.get('url?callback', {<data>}, function(data){
});
with ?callback at the end of url, jquery auto create a random callback function. At your server instead of return normal JSON, you can add wraper callback function around it.
example with php:
$callback = $_GET['callback'];
echo $callback.'('.json_encode(obj).');';
which will become
callback({your return data>});
and your script will receive that.
loadNotices({[{title: 'this is a test'},{title: 'this is another test'}]});
this function call is not correct, do this instead:
loadNotices([{title: 'this is a test'},{title: 'this is another test'}]);
then you can loop through your title like this
for (i = 0; i < titles.length; i++){
alert(titles[i].title);
}
Related
I would like to run some rules against pages. These rules are essentially functions that check the page for information. They can be simple as in 'check if the page has a title tag' or more complex like 'check if all links on the pages are whitelisted based on example.com/allowed_links.json'.
The rules would be run on the page on-demand only and come from a trusted source.
My first approach has been to create a rule service that sends back an javascript array of rules. All the client then has to do is go over the array and run each function in it. The response is a standard object {rule: [name], pass: [true|false], message: [some message about success/failure]}
Since this is on demand only, we fetch the rules from the service and run 'eval' on it.
EDIT: The response from 'mysite/rules' looks like this
RULESYSTEM.rules.push(function1() {...});
RULESYSTEM.rules.push(function2() {...});
...
const RULESYSTEM = {
rules: [],
};
let rules = fetch('mysite/rules')
let rulesscript = await rules.text();
eval(rulescript)
...
//eval will populate the previously declared rules array.
let pass = true;
for(let i=0; i < RULESYSTEM.rules.length; i++) {
let rule = RULESYSTEM.rules[i];
//This obj has only one property. Get that one.
let result = rule();
pass = pass && result.pass;
}
...
This works perfectly fine. However it is receiving a lot of pushback as 'eval' is considered evil and to be avoided at any cost. The security is not an issue here since the source is within the organization itself and thus trusted.
Are there any other ways to implement a system like this.
It would appear that all you're attempting to do is to retrieve JSON data and transforming it into a javascript object.
fetch('mysite/rules')
.then(res=>res.json())
.then(data=>{
//TODO: handle data which is your object/array
console.log(data)
})
Thus no need for eval. Also you need to remember that fetch returns a promise and that rules.text() and rules.json() also returns a promise. The way you've currently written it won't work anyway.
According to MDN
The json() method of the Body mixin takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
To answer your question:
Is it possible to return javascript code as JSON
That's clearly a no, however there are alternatives ! You can simply fetch javacsript as text (as you've done) and programmatically create a script tag, load your javascript text in it and append it to your HTML file.
Or even better, you can simply dynamically create a script tag with the URL of your server endpoint sending javascript and append it to your HTML file.
Something like:
const script = document.createElement("script");
script.onload = function(){
console.log("script loaded");
}
script.src = '/some/url/here';
document.body.appendChild(script);
I am going to add this as an answer. I will use some dummy data you can query based on an endpoint
Route("get-functions")
Response getJSFunctions(List<string> js_to_load){
var options = getData(); //returns a list
var guid = new Guid()
var fp = File.open(guid.toString() + ".js", "w+")
var out = "var fns = [" + options.join("\n") + "];";
fp.write(out);
fp.write(" var runner = options => fns.forEach(fn => fn(options) );");
fp.close()
return new Response({url: guid.toString() + ".js"})
}
Js:
$.json("get-functions", data => {
let script = document.createElement("script");
script.src = data.url;
document.head.appendChild(script)
runner(options);
});
So what is happening is that you build a Temp JS FIle containing all JS Functions you want run, then add that file dynamically to the runtime. Then you have a function which will always be available called runner, which you can immediately call.
Runner will iteratively call each function with a global list of options across the functions, which you can define on the clientside.
Instead of using C#, you can use any serverside or even Javascript if you are using node as your backend. You need DB Access and file creation access on the host machine. You will also want to delete the GUID files ocassionally as they are just one and done use files, so you can delete them all every 5 minutes or something.
I dont have the means right now to create a running sample. I can create something a little later with Python if you like as the backend.
I'm trying to return the header row of a Google spreadsheet using doGet() in a Google App Script that's running as a WebApp. I'm using a HTML form to send the GET request to the WebApp and it's all working except I don't know how to return the headers to my javascript. I'll post my code:
HTML:
<form id="getForm" method="get" action="My URL for WebApp">
<label for="sheetGetID">SheetID</label>
<input type="text" name="sheetGetID" id="sheetGetID" value="">
<button class="ui-btn" onclick='submitGET()'>Submit</button>
</form>
Javascript:
function submitGET() {
var headers = $("getForm").submit();
alert(headers);
}
Google App Script:
function doGet(e) {
//Trying To: Get headers from sheetID and then return to app, then have correct labels for the inputs, then use POST to post.
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName(e.parameter["sheetGetID"]);
//Return the first 3 cells, A1:C1,
var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
return ContentService.createTextOutput(JSON.stringify(headers))
.setMimeType(ContentService.MimeType.JSON);
}
I'm getting a JSON object returned but it's just a text output. My question is how would/could I get the JSON returned and stored as the headers variable?
The return of doGet method must be an HTML.
Build another html page and use the call HtmlService.createTemplateFromFile('newPag.html').evaluate()
Inside your page use the tags and put your server side code manipulating the json object. This way you will create a good look and feel and a good maintanable code.
I got this to work a while ago, I forgot to post the answer just in case anyone else needed it.
You need to output it as a JSON object like the API demo. You also need to append "?prefix=?" to the url when you're doing a $.getJSON() call. The prefix part is to tell the JQuery that it is a JSON object you're receiving.
If anyone has troubles with this just comment and this and I'll post all the code I used.
So on your client end, I'm using JQuery Mobile, I'm not sure how to do it without it, you would do something like:
sheetID = $("#sheetGetID").val();
$.getJSON("https://script.google.com/macros/s/YOUR_KEY_GOES_HERE/exec?prefix=?",
{ sheetGetID: sheetID},
function(results) {
var fields = results.split(",");
//Do something with fields
}
);
}
Where #sheetGetID is the textbox where the user can enter the sheet id for headers.
Note the ?prefix=? appended to the URL, that part is for JQuery to know it's receiving JSON. That part is necessary. The URL is your deployed WebApp.
On the Google App Script side, ie Server side, you'd have something like:
function doGet(request) {
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName(request.parameter["sheetGetID"]);
//Return the first 3 cells, A1:C1,
var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
var result = headers.join();
var content = request.parameters.prefix + '(' +JSON.stringify(result) + ')';
return ContentService.createTextOutput(content)
.setMimeType(ContentService.MimeType.JSON);
}
If you have any questions on how the spreadsheet part works theres plenty of documentation on Google's API's. doGet() is called when you use the $.getJSON(), the return from the G.A.S. needs to be JSON. Most of this is covered in the documentation Google has, some of it I found watching Google Developers Live on youtube. If you are trying to do more stuff I highly recommend checking those sources out.
If you have any more questions about what's being called or parameters you can find it easily enough on Google.
what I am trying to achieve is to AJAX a load of client's data into a page (this works), I then have a company ID in one of the fields brought in. I need to cross check this with a different company table (same database) to replace the company ID on the page with the name instead.
To get this I have set a global javascript variable to blank then fired off the main AJAX request getting all the initial client data then within that parsing loop (client side) I need to fire off a function which will check against the companies table to get the name. My current problem is that the global variable is not being set to the 2nd AJAX result. Here is my code:
var nameresult = "";
function namecheck(id){
var request = new Ajax().sendRequest
('../company_check.php',
{ method: 'GET',
parameters: 'id=' + id,
callback: namecheckReceived }
);
}
function namecheckReceived(xmlHTTP){
var n_data = JSON.parse(xmlHTTP.responseText);
nameresult = n_data[0].name;
}
function client_call(){
var request = new Ajax().sendRequest
('../client_data.php',
{ method: 'GET',
callback: searchReceived }
);
}
function searchReceived(xmlHTTP){
var data = JSON.parse(xmlHTTP.responseText);
for(var i=0; i<data.length; i++)
{
namecheck(data[i].company_id);
/////spit out all the data in a readable format //////
}
}
Notes:
Only one result will be received from the company_check.php hence no
loop in the namecheckRecieved() function.
No errors in the JS console.
The nameresult variable stays as blank and is never
changed, if I alert(nameresult) within the namecheckRecieved()
function it spits out what I want so why is it not changing the
global variable with each loop of the searchRecieved() function?
I'm going to delete all my previous comment and say that you only need one ajax call. And everything should be done on server side. That means get the company Id, and use that to get the name of the company then pass everything back to the client side. From the look of it you are doing A LOT of call backs to the server to get every company name when you could have just done that on your first visit to the server. This way you do not need to worry about doing two ajax call Although from the look of it your doing more than 2 calls, depending on the length of data
Try this
function namecheckReceived(xmlHTTP){
var n_data = JSON.parse(xmlHTTP.responseText);
nameresult = n_data[0].name;
client_call();
}
I'm very, very new to Javascript, and to web programming in general. I think that I'm misunderstanding something fundamental, but I've been unable to figure out what.
I have the following code:
function checkUserAuth(){
var userAuthHttpObject = new XMLHttpRequest();
var url = baseURL + "/userAuth";
userAuthHttpObject.open("POST",url,true);
userAuthHttpObject.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
userAuthHttpObject.onload=function(){
if (userAuthHttpObject.readyState == 4) {
var response = json.loads(userAuthHttpObject.responseText);
return response; //This is the part that doesn't work!
}
};
userAuthHttpObject.send(params);
}
I would love to call it from my page with something like:
var authResponse = checkUserAuth();
And then just do what I want with that data.
Returning a variable, however, just returns it to the userAuthObject, and not all the way back to the function that was originally called.
Is there a way to get the data out of the HttpObject, and into the page that called the function?
Working with AJAX requires wrapping your head around asynchronous behavior, which is different than other types of programming. Rather than returning values directly, you want to set up a callback function.
Create another JavaScript function which accepts the AJAX response as a parameter. This function, let's call it "takeAction(response)", should do whatever it needs to, perhaps print a failure message or set a value in a hidden field and submit a form, whatever.
then where you have "return response" put "takeAction(response)".
So now, takeAction will do whatever it was you would have done after you called "var authResponse = checkUserAuth();"
There are a couple of best practices you should start with before you continue to write the script you asked about
XMLHTTTPRequest() is not browser consistent. I would recommend you use a library such as mootools or the excellent jquery.ajax as a starting point. it easier to implement and works more consistently. http://api.jquery.com/jQuery.ajax/
content type is important. You will have have problems trying to parse json data if you used a form content type. use "application/json" if you want to use json.
true user authorization should be done on the server, never in the browser. I'm not sure how you are using this script, but I suggest you may want to reconsider.
Preliminaries out of the way, Here is one way I would get information from an ajax call into the page with jquery:
$.ajax({
//get an html chunk
url: 'ajax/test.html',
// do something with the html chunk
success: function(htmlData) {
//replace the content of <div id="auth">
$('#auth').html(htmlData);
//replace content of #auth with only the data in #message from
//the data we recieved in our ajax call
$('#auth').html( function() {
return $(htmlData).find('#message').text();
});
}
});
I need help. I need to call a Java function "getLocCountByWhId()" in a Java class; this Java function is being called within a JavaScript in a for-loop. I need to pass in a JavaScript variable as a parameter into this Java function "getLocCountByWhId()". I have been struggling for a week and reading numerous website to get some guidelines but I have not been able to resolve the problem. Thank you in advance for your help. The code is listing below:
<script language="JavaScript">
<!--
function onCreatePO()
{
<%long jspAllocId = alloc.getId();%>;
var recItemId = ""; // Local variable for item id.
var recWhId = ""; // Local variable for warehouse id.
for (var i=0, j=document.what_if_summary.elements.length; i<j; i++)
{
var recStr = document.what_if_summary.elements[i].value;
var splitStr = new Array();
splitStr = recStr.split('^');
recItemId = splitStr[1]; // Get the field value for Item_ID.
recWhId = splitStr[2]; // Get the field value for Warehouse_ID.
// Get a database connection with global 'conn' object and retrieve store count.
<%AfsGetVDSCountByWarehouseBean.setConnection(conn);%>;
// The below assignment from JavaScript variable to JSP variable do not work
// because of a second JavaScript tag. How can I get around this ?
//<% String jspItemId = "<script>document.writeln(recItemId)</script>"; %>
//<% String jspWhId = "<script>document.writeln(recWhId)</script>"; %>
currentStoreCount = <%= AfsGetVDSCountByWarehouseBean.getLocCountByWhId(jspAllocId, jspItemId, jspWhId)%>;
}
}
//-->
</script>
// I get this example of assigning Javascript to JSP variable but I got double tag problem.
<script>
var v="Roseindia";
</script>
<% String st="<script>document.writeln(v)</script>";
out.println("value="+st); %>
What you are trying to do is not possible, and (sorry!) reflects a basic misunderstanding as to how server-side code such as JSP (or ASP, PHP, etc) works.
A JSP page is basically a Java servlet running on the web server that dynamically generates a web page and returns it to the browser. The resulting web page may contain HTML, CSS, JavaScript, etc., but to the Java code all of that is just text. The Java/JSP code cannot understand or interact with the JavaScript because the JavaScript doesn't run on the web server, it is just more text to be sent as part of the response back to the browser.
When the browser gets the response it will display the web page and execute any JavaScript.
Further reading (I wouldn't put too much faith in what you read at the RoseIndia site):
http://www.ibm.com/developerworks/java/tutorials/j-introjsp/
http://www.oracle.com/technetwork/articles/javase/servlets-jsp-140445.html
http://java.sun.com/developer/onlineTraining/JSPIntro/