I am trying to create a tabulator 4.1 table with columns that will load via AJAX. Preferably without jQuery, although it could be used if it makes a large difference. I have tried the following to no avail:
table.setColumns("ajaxr.php?act=GetTabuColumns&vals=data");
and
$("#display").tabulator("setColumns", "ajax.php?act=GetTabuColumns&vals=data");
I've also tried doing separate ajax request with plain Javascript as well as a jQuery ajax request. The date would load as a json encoded array, but it would throw the following error.
Uncaught TypeError: t.forEach is not a function
at t.setColumns (tabulator.min.js:2)
at t.c.setColumns (tabulator.min.js:4)
at XMLHttpRequest.xmlhttp.onreadystatechange ((index):71)
I'm fairly new to javascript so it could me I'm making a basic mistake. How should this be done?
My basic setup is as follows:
function datatablemaker(table){
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var newcolumns = this.responseText;
var table = new Tabulator("#display", {
columns:[
{title:'ID', field:'ID', sorter:'number'},...
{title:'Create Time', field:'Create Time', sorter:'string'}
],
});
table.setData("ajax.php?act=GetTabuData&vals=data");
table.setColumns(newcolumns);
}
};
xmlhttp.open("GET",'ajax.php?act=GetTabuColumns&vals=data',true);
xmlhttp.send();
};
document.getElementById("View").addEventListener("click", datatablemaker);
EDIT:
I got it to work if I used JSON.parse, but I know that there should be a better way to do this. i.e.
var newcolumns = JSON.parse(this.responseText);
There is no build in way to do this at the moment, that will be coming in the 4.2 release later in the month.
in the mean time making an ajax request and passing the column array into the setColumns function is the best approach.
Related
I have written some JavaScript to send a request to a php file which can query or post to a database. I have tried using GET and POST.
function action(theAction) {
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "queryDB.php", true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function () {
// The variable xmlhttp not available here. But since this function is a member of xmlhttp, this=xmlhttp
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
document.getElementById("result").innerHTML =
document.getElementById("result").innerHTML + " " + this.responseText;
}
}
xmlhttp.send("p1=post&p2=" + theAction);
}
function showActivity () {
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
document.getElementById("result").innerHTML = this.responseText;
}
xmlhttp.open("GET", "queryDB.php?p1=list");
xmlhttp.send();
}
Both methods work fine but they both can be imitated by simply writing the URL of my php file followed by suitable parameters into a browser address bar. So for the GET example I could write in
https://patience5games.com/php/queryDB.php?p1=list
and I get a little report in the browser window.
This means that it is quite easy for hackers to post fake data to my database. How can I prevent that?
I want to send a message in not such an obvious way. One bodge solution using the POST method would be to have xmlhttp.setRequestHeader("Content-Type", "my message"); which I could decode at the other end. I think. But surely there must be a better way than that?
I am using the following code in an HTML webpage:
var request = new XMLHttpRequest();
var url= "my azure httptrigger";
request.open('GET', url, true);
request.onload = function () {
// Begin accessing JSON data here
var data = this.response;
if (request.status >= 200 && request.status < 400) {
document.getElementById('results').innerHTML = data;
function2();
} else {
console.log('error');
}
}
request.send();
In my API (httptrigger in Azure Functions) I use:
context.res = {
body: bodyStuff,
headers: {
'Content-Type': 'text/html; charset=utf-8'
}
}
to determine the data to send back from the API. This means when I end the Azure function - the data sent in the body in context.res is sent to my webpage and displayed.
This works fine and as planned. However, what I am looking for is the ability to send data back in two parts.
(I attempted to define context.res twice but this didn't work as the second definition overrode the first)
Is there an effective way to do this?
In essence, a user hits my API and I want to send partial data to the webpage from the API halfway through the function, and then more data at the end. This is to make the user experience on the webpage quicker than waiting for all the data to load/function to finish.
What you are trying to do is something that can't be done just with azure functions.
Seems like you want to divide the payload without dividing the logic, and that won't work for the HTTP protocol.
This protocol means 1 request, and 1 answer. Which means that you need to select a different protocol to make this happen.
You could have the option to use sockets, to use streamable data or other methods, but you can't append data to an HTTP request, once it has been fired.
And the azure functions are an implementation on top of HTTP, that is why the context.res is being overridden, because you can only answer one thing.
What you could do is to make several calls instead of a very long and big one. And try to divide the "quick" logic from the "slow" one, so that you can load elements quicker.
I'm running GM_xmlhttpRequest (in a Greasemonkey script) and storing the responseText into a newly created HTML element:
var responseHTML = document.createElement('HTML');
...
onload: function() { responseHTML.innerHTML = response.responseText; }
And then I am trying to find an element in responseHTML:
console.log(responseHTML.getElementsByTagName('div'));
console.log(responseHTML.getElementById('result_0'));
The first works fine, but not the second. Any ideas?
Use DOMParser() to convert responseText into a searchable DOM tree.
Also, your attempts to search/use anything derived from responseText, must occur inside the onload function.
Use code like this:
GM_xmlhttpRequest ( {
...
onload: parseAJAX_ResponseHTML,
...
} );
function parseAJAX_ResponseHTML (respObject) {
var parser = new DOMParser ();
var responseDoc = parser.parseFromString (respObject.responseText, "text/html");
console.log (responseDoc.getElementsByTagName('div'));
console.log (responseDoc.getElementById('result_0'));
}
Of course, also verify that a node with id result_0 is actually in the returned HTML. (Using Firebug, Wireshark, etc.)
getElementById is not a method of HTML elements. It is a method of the document node. As such you can't do:
div.getElementById('foo'); // invalid code
You can implement your own function to search the DOM by recursively going through children. On newer browsers you can even use the querySelector method. For minimal development you can use libraries like jQuery or sizzle.js (the query engine behind jQuery).
There is no need to store the response in an element neither use DOMParser()
Just set the responseType to 'document' and the response will be parsed automatically and stored in the responseXML
Example:
var ajax = new XMLHttpRequest();
ajax.open('get','http://www.taringa.net');
ajax.responseType = 'document';
ajax.onload = function(){
console.log(ajax.responseXML); //And this is a document which may execute getElementById
};
ajax.send();
I have an XAgent I have created that works just fine via window.location but I can't get it to work via AJAX. This agent is called from a delete button on a popup div, so rather than writing to my responseStream in my XAgent, I'd prefer to just run my agent and close my popup via javascript when it is finished.
My XAgent is called by the URL doc.$DBPath.value + "/xAgent_DeleteDemand.xsp?open&id=" + doc.$DocUNID.value and looks like this:
javascript:importPackage(foo);
try {
var url:java.lang.String = context.getUrl().toString();
print(url);
if (param.containsKey("id")) {
var unid = param.get("id");
} else {
throw "No unid given";
}
XAgent.deleteDemand(unid);
} catch (e) {
print(e);
}
My actual code is in the foo package but that doesn't seem relevant because I'm not even getting my URL printed. I can say the the URL being generated and called works just fine using window.location so it is safe to assume that the problem is elsewhere.
I have a sneaking suspicion that maybe context doesn't have any meaning when called via AJAX from a non XPage app, but I don't know for sure.
I don't think there is anything special about my AJAX code but here it is just in case. It has been working fine for a long time.
function createAJAXRequest(retrievalURL, responseFunction) {
if (window.ActiveXObject) {
AJAXReq = new ActiveXObject("Microsoft.XMLHTTP");
} else if (window.XMLHttpRequest) {
AJAXReq = new XMLHttpRequest();
}
showHideIndicator("block")
var currentTime = new Date()
AJAXReq.open("GET", retrievalURL + "&z=" + currentTime.getTime());
AJAXReq.onreadystatechange = eval(responseFunction);
AJAXReq.send(null);
}
I'm not sure what the immediate problem would be, but as some troubleshooting steps:
The resultant URL is just server-relative and not on a different server+protocol combination, right?
Do you see anything on the browser's debug console when clicking the button?
Is there an entry in the browser's debug Network panel for the request at all?
How can an Omnibox extension create and post form data to a website and then display the result?
Here's an example of what I want to do. When you type lookup bieber into the Omnibox, I want my extension to post form data looking like
searchtype: all
searchterm: bieber
searchcount: 20
to the URL http://lookup.com/search
So that the browser will end up loading http://lookup.com/search with the results of the search.
This would be trivial if I could send the data in a GET, but lookup.com expects an HTTP POST. The only way I can think of is to inject a form into the current page and then submit it, but (a) that only works if there is a current page, and (b) it doesn't seem to work anyway (maybe permissions need to be set).
Before going off down that route, I figured that somebody else must at least have tried to do this before. Have you?
You could do this by using the omnibox api:
chrome.omnibox.onInputChanged.addListener(
function(text, suggest) {
doYourLogic...
});
Once you have you extension 'activated' due to a certain keyword you typed you can call something like this:
var q = the params you wish to pass
var url = "http://yourSite.com";
var req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onreadystatechange = function() {
if (req.readyState == 4) {
callback(req.responseXML);
}
}
req.send(q);