thanks in advance for your help! I am working with (and super new to) JavaScript, node.js with express, and sqlite3. I am trying to make an AJAX request to get a list of all the messages that have been posted to the chatroom page:
var meta = document.querySelector('meta[name=roomName]');
var roomName = meta.content;
window.addEventListener('load', function(){
var intervalID = setInterval(updateMessages, 4000);
}, false);
function updateMessages() {
var req = new XMLHttpRequest();
req.open('GET', '/' + roomName + '/messages.json', true);
req.send();
document.getElementById('messages').innerHTML = req.responseText;
}
Two questions: 1. I think I should be using setTimeout instead of setInterval. How would I go about switching to using this method? 2. Is the server-side code below that corresponds to the code above correct? How do I get access to the data that comes back after this request?
app.get('/:roomName/messages.json', function(request, response){
var roomName = request.params.roomName;
var sql = "SELECT ALL body FROM messages where room="+roomName+";";
conn.query(sql, function(error, result) {
if(error) {
console.log("There was an error.");
}
response.send(result);
});
});
setInterval is the appropriate thing to use here.
However, keep in mind that you will never see any messages because AJAX is asynchronous, so req.responseText won't have anything. You should use a readystatechange event:
req.open(......);
req.onreadystatechange = function() {
if( this.readyState == 4) {
document.getElementById('messages').innerHTML = this.responseText;
}
};
req.send();
Related
I'am trying to parse site. The site (i suppose) using scripts and data bases to load data from (dynamically?). And this is my problem... I am trying to grab data through C# (unfortunately i don't have access to code right now) or JS. And it seems like either C# and JS, get only template of the site, but don't wait until all scripts executed. So this is my question, is there any way to get ALL html source? Maybe call scripts somehow. Or make a request, wait for 10 seconds, and then write source html data into variable?
Here is my JS code.
function request(link)
{
var xhr = new XMLHttpRequest();
xhr.open('GET', link, true);
xhr.onreadystatechange = function() .
{console.log(xhr.readyState);};
xhr.send();
let data = xhr.responseText;
var tempDiv = document.createElement('div');
tempDiv.innerHTML = data.replace(/<script(.|\s)*?\/script>/g,
'');
return tempDiv;
}
function loadFile(url, timeout, callback)
{
var args = Array.prototype.slice.call(arguments, 3);
var xhr = new XMLHttpRequest();
xhr.ontimeout = function () {
console.error("The request for " + url + " timed out.");
};
xhr.onload = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
callback.apply(xhr, args);
} else {
console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, true);
xhr.timeout = timeout;
xhr.send(null);
let data = xhr.responseText;
return data;
}
function showMessage (message) {
console.log(message + this.responseText);
}
function include(scriptUrl)
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", scriptUrl);
xmlhttp.onreadystatechange = function()
{
if ((xmlhttp.status == 200) && (xmlhttp.readyState == 4))
{
eval(xmlhttp.responseText);
}
};
xmlhttp.send();
let data = JSON.parse(xmlhttp.responseText);
var tempDiv = document.createElement('div');
tempDiv.innerHTML = data.replace(/<script(.|\s)*?\/script>/g,
'');
return tempDiv;
}
All this functions do not work as i want.
This isn't really practical - you're trying to load an HTML page, all associated scripts, then run them on the HTML page as if they were in a proper browser environment, but within your current browser session.
This sort of thing is feasible with the jsdom library if you were running on the server-side (NodeJS), because it simulates browser behaviour: https://github.com/jsdom/jsdom. So you could do
JSDOM.fromURL("https://example.com/", { runScripts: "dangerously" }).then(dom => {
console.log(dom.serialize()); //turn the page back into HTML
});
...to get the whole thing.
I have a problem with my code and I'm struggling finding why it doesn't work as expected.
I have an API that returns data async. and I want the frontend side to add that data as soon as it's being received. What I expect is an API that returns, say 200 items, then javascript to load those 200 items to a table, meanwhile the API keeps returning another 200 items, and then javascript appends them to the table, and so on until there is no more data left.
I'm using vanilla Javascript 5, prototype-based MVC pattern. Perhaps I'm not getting something simple or its far more complex than I expected.
resultView.js
//this function gets executed by some other code not relevant
ResultView.prototype.execute = function(serverName, databaseName, query){
var response = resultController.getData(serverName, databaseName, query);
console.log("response: ", response); //prints undefined
response.done(function(data){ // Uncaught TypeError: Cannot read property 'done' of undefined
console.log("response done: ", response); //doesn't even execute
data.forEach(populateTable); //this code should populates the table
});
}
resultController.js
ResultController.prototype.getData = function(serverName, databaseName, query){
return resultModel.getData(serverName, databaseName, query);
};
resultModel.js
ResultModel.prototype.getData = function (serverName, databaseName, query) {
var dataSend = {
//the code that is being sent
};
var result = "";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onprogress = function () {
result += xhr.responseText;
if(xhr.readyState == 4){
console.log("return: ", result); //shows the results properly each time they are received
return result; //not sure about this return
}
}
xhr.send(JSON.stringify(dataSend));
};
}
I know the data is being received in the API, and the data is returned properly in the front end, the issue must be how I am trying to handle it.
Currently, the results I am getting on the console.log at resultModel.js are the expected, the problem seems to be when calling it from resultView.js, I guess when the function calls response.done(), but I am unable to fix it.
Anyone knows how can I approach a solution?
Thanks in advance.
EDIT:
Partially thanks to Ionut, I've managed to make the resultView.js return better datas, but I still have the problem at the resultView.js, when I try to use response.done(...) it tells me it can't do done() of undefined, but the data should be able to be returned. This is my code in resultModel.js now, the rest remains unchanged.
resultModel.js
var xhr = new XMLHttpRequest();
console.log("Sending the request...");
xhr.open("POST", urlBase + "QueryResults", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
console.log("return: ", xhr.responseText); //data is logged properly
return xhr.responseText; //it should be returned properly
}
};
xhr.send(JSON.stringify(queryRequest));
You should add a callback function to manage the full response.
If you want to implement something like lazy-loading you should request your API to send you batches of a smaller number of items, you process them then request more until you get them all.
Here is a basic http request.
console.log('Sending the request ...');
var xhr = new XMLHttpRequest();
xhr.open('GET', "//ipinfo.io/json", true);
xhr.send();
xhr.onreadystatechange = processRequest;
function processRequest(e) {
console.log('Getting the response ...');
if (xhr.readyState == 4 && xhr.status == 200) {
var response = JSON.parse(xhr.responseText);
console.log('Your ip address is ' + response.ip);
} else {
console.log('Error state=' + xhr.readyState + ', status=' + xhr.status);
}
}
At the moment I am calling a function on a setInterval basis.
This function makes a XMLHttpRequest to my server to get update info. If there is an update available I update an image (using canvas element).
Is this the optimum way to do this sort of thing?
My code:
Calling code:
function StartFeedUp() {
if (tmrStartFeedUp) window.clearInterval(tmrStartFeedUp);
tmrStartFeedUp = setInterval(GetNextImage, 330);
}
My called function:
var isProcess = false;
function GetNextImage() {
try {
if (!isProcess) {
isProcess = true;
var urlTS = '/Cloud/isNewFrames.ashx?alias=' + alias + '&version=' + version + '&guidlogon=' + guidlogon;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", urlTS, true);
xmlhttp.timeout = 200;
xmlhttp.send();
var nextts = xmlhttp.responseText;
}
isProcess = false;
}
catch (err) {
isProcess = false;
document.getElementById("divMode2").innerHTML = err;
}
}
Other than repeating the XHR call, you can use HTML5 Web Sockets which allows you to maintain a connection to the server, whereby the server would push data as and when needed. Web Sockets are relatively new and so aren't supported by old browsers.
Your XHR is asyncronous so you should be listening on the onreadystatechange event instead of always expecting the response to be available directly after the send() call:
xmlhttp.open("GET", urlTS, true);
xmlhttp.timeout = 200;
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
console.log("received " + xmlhttp.responseText);
}
}
xmlhttp.send();
I am trying to figure out the best way to handle this scenario. Basically I want the flow to work like this:
1.) Get configuration data from server (async)
2.) Run doStuff() after configuration data is received (async)
3.) Run postResults after doStuff() completes
Currently I seem to have this flow working using PubSub.js, however I am trying to figure out how I can provide the results from config data (#1) to postResults (#3). While I seem to have the flow working with PubSub, I'm not sure how to access the configuration (#1) callback data from postResults (#3)
Here is a code summary:
PubSub.subscribe('config', doStuff());
fetchConfigurations();
function fetchConfigurations () {
var req = new XMLHttpRequest();
var url = CONFIGURATION_SERVER_URL;
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
var configObject = eval('(' + req.responseText + ')');
PubSub.publish('config', configObject);
} else {
console.log("Requesting config from server: " + url);
}
}
req.open("GET", url, true);
req.send(null);
}
function doStuff() {
PubSub.subscribe('results', postResults);
var results = {};
// do some async work...
results['test1'] = "some message";
results['test2'] = "another message";
PubSub.publish('doStuff', results);
}
function postResults (doStuffId, doStuffData) {
var req = new XMLHttpRequest();
var url = TEST_RESULTS_URL; // I want to get this from the configObject is get in fetchConfigurations
req.open("POST",url,true);
req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
req.send(doStuffData['test1'] + doStuffData['test2']);
}
Using promise seemed like the a better fit for this problem instead of pub/sub, here is the implementation I ended up using:
https://github.com/hemanshubhojak/PromiseJS
I have 5 drop down lists which is dynamic in nature. But the only problem is all the option values are being fetched from mysql database and i really want the user to know that the query is happening at the backend and he should wait by displaying a gif or a line saying "loading.. " .
I've been looking all over for this and similar questions have been posted by others but i don't seem to get it working . Please help me out. Can somebody please give a easy solution?
Thanks.
I've placed an example here:
http://jsfiddle.net/cMEaM/embedded/result/
I've kept as much of the existing code the same so you should still recognise it. The getXMLHTTP function is the same:
function getXMLHTTP() {
//function to return the xml http object
var xmlhttp = false;
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
xmlhttp = false;
}
}
}
return xmlhttp;
}
There's a new sendGet function to handle the XHR request, which takes success and error callbacks.
function sendGet(url, onSuccess, onError) {
var req = getXMLHTTP();
var method = "GET";
if (req) {
req.onreadystatechange = function() {
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
onSuccess(req);
} else {
onError(req);
}
}
}
req.open(method, url, true);
req.send(data);
}
}
I borrow a throbber from Wikipedia to display when the data is loading.
var throbberHtml = "<img src='http://upload.wikimedia.org/wikipedia/en/2/29/Throbber-Loadinfo-292929-ffffff.gif'>";
And these are the new getXXX functions which replace the <select> with the throbber while the data is loading:
function getState(countryId) {
var div = document.getElementById('statediv');
var oldInnerHTML = div.innerHTML;
var onSuccess = function(req) {
div.innerHTML = req.responseText;
};
var onError = function(req) {
div.innerHTML = oldInnerHTML;
alert("There was a problem while using XMLHTTP:\n" + req.statusText);
};
div.innerHTML = throbberHtml;
sendGet("findState.php?country=" + countryId, onSuccess, onError);
}
function getCity(countryId, stateId) {
var div = document.getElementById('citydiv');
var oldInnerHTML = div.innerHTML;
var onSuccess = function(req) {
div.innerHTML = req.responseText;
};
var onError = function(req) {
div.innerHTML = oldInnerHTML;
alert("There was a problem while using XMLHTTP:\n" + req.statusText);
};
div.innerHTML = throbberHtml;
sendGet("findCity.php?country=" + countryId + "&state=" + stateId,
onSuccess, onError);
}
There are other improvements that could be made, but I tried to keep in the sprit of your existing code as much as possible.
E.g. you can see that most of code in the getXXX functions is the same, so you could refactor these to use mostly the same code. Also, using a JS framework such as jQuery will replace the XHR code with better, more cross-browser compatible code. It's usually always better to avoid reinventing the wheel when it comes to code!
And you may possibly decide that sending the HTML for a <select> tag is not the best data format for the XHR. You might go with JSON which would decouple your presentation from the data.