I've been doing a lot of searching the last few days on AJAX.
I see why I postponed learning that particular area of JavaScript, it seems a little complex.
I notice that most questions and answers are formulated around how to SEND data via POST, but I can't find any detailed examples of what to DO with the data once the POST has completed.
I want to use JavaScript rather than php to process the data server side, and I haven't found any useful Q/A. tutorials or discussion on the topic, excluding PHP. I figure I have to ask the specific question myself.
To help visualize my question I'll give the specific example that stimulates my question.
I have a file containing a list of tasks pending, and a list of tasks completed.
The functionality in this list is that when a user clicks on the task, it is inserted into a database, where it is associated with the user.
Multiple users see this page and anyone logged in can "log" a task completed by clicking on the list item. The list item also opens another page containing more details on the item and cascades to some other functions while logging the completion and user data to the database.
<h3>To Do!</h3>
<ol class="pending>
<li><a class="pending_task" href="localhost://nextstep.html">Task Three</a></li>
<li><a class="pending_task" href="localhost://nextstep.html">Task Five</a></li>
<li><a class="pending_task" href="localhost://nextstep.html">Task Six</a></li>
</ol>
On the same page is the "Completed" task list which is populated when the pending is clicked:
<h3>Completed!</h3>
<ol class="completed">
<li><a class="completed_task" href="localhost://nextstep.html">Task One</a></li>
<li><a class="completed_task" href="localhost://nextstep.html">Task Two</a></li>
<li><a class="completed_task" href="localhost://nextstep.html">Task Four</a></li>
</ol>
The code which manages that:
$(document).ready(function(){
$('.pending').on('click', function(){
evt.preventDefault();
$(this).toggleClass("pending").parent().appendTo("ol.completed");
});
});
My goal is to have the static html updated server side, when a task has been completed, so that when the page reloads or is accessed by another user, the new configuration of "Pending" vs "Completed", is current. As a friend explained, I can't just write the updated file to server from the client side, so I realized AJAX was the best solution. Send the updated information to the server and have a script on the server side rewrite the source file when a task has been clicked as complete. I have done the $_POST[key] functionality with PHP, but I have been more impressed with JavaScript so I want to learn how to do this purely in JavaScript.
Based on my new understanding, I changed the code a bit:
$(document).ready(function(){
$('.pending').on('click', function(){
evt.preventDefault();
$(this).toggleClass("pending").parent().appendTo("ol.completed");
var newData = $("ul.pending") + $("ul.completed");
console.log(newData);
var xhr = $.ajax({ //jshint ignore: line
method:'POST',
data: newData,
url:"update.js",
success: function(){
console.log("completed POST");
},
dataType: 'html',
}); //xhr
});
});
So I get this far and I'm confused by how to properly activate the receiving script so that the file is rewritten and also perhaps reload the file so that the persistence of the change is maintained.
I'm looking to understand the details of handling the POST data, without using PHP or a DATABASE. I just want to rewrite the HTML with the updated changes to the <ol> items.
If this is not the proper forum for that or there are resources that would help enlighten me, I would appreciate advice on how to find the best resources.
Thank You.
UPDATE:
I am using node.js on the server side. The HTML is being presented via an app.js so the idea of doing server side operations is deeply connected to using node.js
Update 2:
I'm a little lost in the process of the POST/response dynamic.
The script initiating the POST will get a response, of that I am clear.
So if I want the POSTEd html to be manipulated on the server side, then the response will come from the node.js indicating that the file has been rewritten, as requested by the POST? So the response can/will be a result of something I code on the server side.
My question remains though: How do I manipulate the POST data on the server side?
In PHP it is $_POST[key]. What is it in JavaScript?
And since I am sending HTML as the POST data, how should I handle it? Will it be a hash {key, value} or is it in some other form? I can't find these details in my google searching. I'm not sure how to phrase the question to get the answer I need.
And further, what triggers the node script to execute on the server side once it has been addressed y the POST call? Or am I overthinking that part?
You seem to misunderstand the server/client model. You cannot use html/javascript to change things in your server, for that you will have to use your PHP server.
You can have a javascript server with Node.js https://nodejs.org , but that will probably replace your current PHP server. You can have multiple server in different languages, but that will make your project a bit harder to maintain.
Now about the AJAX request, it's like any other http request. You will send a header with your meta data and you will receive the answer from the server. If you want the server to do something (like write to a file or DB) every time it receives an specific request, you will need to code that by yourself.
UPDATE
You edited your question, now I know you're using nodejs. Here are a few extra info that might help
1 - Take a look at this question (it's really basic stuff and might help a lot)
Basic Ajax send/receive with node.js
2 - Change this line:
var newData = $("ul.pending") + $("ul.completed");
to this:
var newData = $("ul.pending").html() + $("ul.completed").html();
3 - This question will show you how to handle POST in node How do you extract POST data in Node.js?
This was the final code I developed after coming to an understanding of AJAX:
http.createServer(function(req, res){
if ((req.method === 'POST') && (req.url === '/result')){
var body = '';
res.statusCode = 200;
res.end("Message Received!");
req.on('data', function(data){
body += data;
});
req.on('end', function () {
var suffix = getDateTime();
var output = "Links" + "_" + suffix + ".html";
// Copy the original First
fs.writeFileSync(output, fs.readFileSync("./Links.html"));
// Overwrite the original file with the updated list configuration
fs.writeFileSync("./Links.html", body, 'utf-8');
});
} else if (req.method === 'GET') { // Reorganized 2017 01 05 # 2237
// Serve the static html
var filename = req.url || "Links.html";
var ext = path.extname(filename);
var localPath = __dirname;
var validExtensions = {
".html": "text/html",
".css": "text/css",
".js": "application/javascript",
".txt": "text/plain",
".jpg": "image/jpeg",
".gif": "image/gif",
".png": "image/png",
".woff": "application/font-woff",
".woff2": "application/font-woff2",
".ico": "image/x-icon",
"" : "text/html"
};
var validMimeType = true;
var mimeType = validExtensions[ext];
if (checkMimeType){
validMimeType = validExtensions[ext] !== undefined;
}
if (validMimeType){
localPath += filename;
fs.exists(localPath, function(exists){
if (exists){
getFile(localPath, res, mimeType);
} else {
console.log("File not found: " + localPath);
res.writeHead(404);
res.end();
}
});
} else {
console.log("Invalid file extension detected: " + ext + "(" + filename + ")");
}
}
}).listen(port, serverURL);
function getFile(localPath, res, mimeType){
fs.readFile(localPath, function(err, contents){
if (!err) {
res.setHeader("Content-Length", contents.length);
if (mimeType !== undefined){
res.setHeader("Content-Type", mimeType);
}
res.statusCode = 200;
res.end(contents);
} else {
res.writeHead(500);
res.end();
}
});
}
The other relevant code:
/* jslint node: true, browser: true */ /* globals $:false */
"use strict";
var ajax_url ="/result";
$(document).ready(function(){
$('.source_link').on('click', function(){
//evt.preventDefault();
$(this).toggleClass("source_link downloaded").parent().appendTo("ol.downloaded");
var front = "<!doctype html><html>";
var head1 = "<head><link rel=\"stylesheet\" href=\"link.css\">";
var head2 = "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>";
var head3 = "<script src=\"links.js\"></script>";
var head4 = "<script src=\"nameanchor.js\"></script>";
var head5 = "</head><body>";
var bottom = "</body></html>";
var newData = front + head1 + head2 + head3 + head4 + head5 + "<ol class=\"pending\">" + $('ol.pending').html() +
"</ol>" + "<ol class=\"downloaded\">" + $('ol.downloaded').html() + "</ol>" + bottom;
$.ajax({
method:'POST',
data: newData,
url: ajax_url,
success: function(result, status, jqxhr){
console.log("Response: " + jqxhr.responseText);
console.log("POST status: " + status);
},
dataType: 'html',
});
});
});
Related
I'm making a web app that requires that I check to see if remote servers are online or not. When I run it from the command line, my page load goes up to a full 60s (for 8 entries, it will scale linearly with more).
I decided to go the route of pinging on the user's end. This way, I can load the page and just have them wait for the "server is online" data while browsing my content.
If anyone has the answer to the above question, or if they know a solution to keep my page loads fast, I'd definitely appreciate it.
I have found someone that accomplishes this with a very clever usage of the native Image object.
From their source, this is the main function (it has dependences on other parts of the source but you get the idea).
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function() {_that.good();};
this.img.onerror = function() {_that.good();};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() { _that.bad();}, 1500);
}
}
This works on all types of servers that I've tested (web servers, ftp servers, and game servers). It also works with ports. If anyone encounters a use case that fails, please post in the comments and I will update my answer.
Update: Previous link has been removed. If anyone finds or implements the above, please comment and I'll add it into the answer.
Update 2: #trante was nice enough to provide a jsFiddle.
http://jsfiddle.net/GSSCD/203/
Update 3: #Jonathon created a GitHub repo with the implementation.
https://github.com/jdfreder/pingjs
Update 4: It looks as if this implementation is no longer reliable. People are also reporting that Chrome no longer supports it all, throwing a net::ERR_NAME_NOT_RESOLVED error. If someone can verify an alternate solution I will put that as the accepted answer.
Ping is ICMP, but if there is any open TCP port on the remote server it could be achieved like this:
function ping(host, port, pong) {
var started = new Date().getTime();
var http = new XMLHttpRequest();
http.open("GET", "http://" + host + ":" + port, /*async*/true);
http.onreadystatechange = function() {
if (http.readyState == 4) {
var ended = new Date().getTime();
var milliseconds = ended - started;
if (pong != null) {
pong(milliseconds);
}
}
};
try {
http.send(null);
} catch(exception) {
// this is expected
}
}
you can try this:
put ping.html on the server with or without any content, on the javascript do same as below:
<script>
function ping(){
$.ajax({
url: 'ping.html',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
You can't directly "ping" in javascript.
There may be a few other ways:
Ajax
Using a java applet with isReachable
Writing a serverside script which pings and using AJAX to communicate to your serversidescript
You might also be able to ping in flash (actionscript)
You can't do regular ping in browser Javascript, but you can find out if remote server is alive by for example loading an image from the remote server. If loading fails -> server down.
You can even calculate the loading time by using onload-event. Here's an example how to use onload event.
Pitching in with a websocket solution...
function ping(ip, isUp, isDown) {
var ws = new WebSocket("ws://" + ip);
ws.onerror = function(e){
isUp();
ws = null;
};
setTimeout(function() {
if(ws != null) {
ws.close();
ws = null;
isDown();
}
},2000);
}
Update: this solution does not work anymore on major browsers, since the onerror callback is executed even if the host is a non-existent IP address.
To keep your requests fast, cache the server side results of the ping and update the ping file or database every couple of minutes(or however accurate you want it to be). You can use cron to run a shell command with your 8 pings and write the output into a file, the webserver will include this file into your view.
The problem with standard pings is they're ICMP, which a lot of places don't let through for security and traffic reasons. That might explain the failure.
Ruby prior to 1.9 had a TCP-based ping.rb, which will run with Ruby 1.9+. All you have to do is copy it from the 1.8.7 installation to somewhere else. I just confirmed that it would run by pinging my home router.
There are many crazy answers here and especially about CORS -
You could do an http HEAD request (like GET but without payload).
See https://ochronus.com/http-head-request-good-uses/
It does NOT need a preflight check, the confusion is because of an old version of the specification, see
Why does a cross-origin HEAD request need a preflight check?
So you could use the answer above which is using the jQuery library (didn't say it) but with
type: 'HEAD'
--->
<script>
function ping(){
$.ajax({
url: 'ping.html',
type: 'HEAD',
success: function(result){
alert('reply');
},
error: function(result){
alert('timeout/error');
}
});
}
</script>
Off course you can also use vanilla js or dojo or whatever ...
If what you are trying to see is whether the server "exists", you can use the following:
function isValidURL(url) {
var encodedURL = encodeURIComponent(url);
var isValid = false;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
isValid = data.query.results != null;
},
error: function(){
isValid = false;
}
});
return isValid;
}
This will return a true/false indication whether the server exists.
If you want response time, a slight modification will do:
function ping(url) {
var encodedURL = encodeURIComponent(url);
var startDate = new Date();
var endDate = null;
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
type: "get",
async: false,
dataType: "json",
success: function(data) {
if (data.query.results != null) {
endDate = new Date();
} else {
endDate = null;
}
},
error: function(){
endDate = null;
}
});
if (endDate == null) {
throw "Not responsive...";
}
return endDate.getTime() - startDate.getTime();
}
The usage is then trivial:
var isValid = isValidURL("http://example.com");
alert(isValid ? "Valid URL!!!" : "Damn...");
Or:
var responseInMillis = ping("example.com");
alert(responseInMillis);
const ping = (url, timeout = 6000) => {
return new Promise((resolve, reject) => {
const urlRule = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&##/%?=~_|!:,.;]+[-A-Za-z0-9+&##/%=~_|]');
if (!urlRule.test(url)) reject('invalid url');
try {
fetch(url)
.then(() => resolve(true))
.catch(() => resolve(false));
setTimeout(() => {
resolve(false);
}, timeout);
} catch (e) {
reject(e);
}
});
};
use like this:
ping('https://stackoverflow.com/')
.then(res=>console.log(res))
.catch(e=>console.log(e))
I don't know what version of Ruby you're running, but have you tried implementing ping for ruby instead of javascript? http://raa.ruby-lang.org/project/net-ping/
let webSite = 'https://google.com/'
https.get(webSite, function (res) {
// If you get here, you have a response.
// If you want, you can check the status code here to verify that it's `200` or some other `2xx`.
console.log(webSite + ' ' + res.statusCode)
}).on('error', function(e) {
// Here, an error occurred. Check `e` for the error.
console.log(e.code)
});;
if you run this with node it would console log 200 as long as google is not down.
You can run the DOS ping.exe command from javaScript using the folowing:
function ping(ip)
{
var input = "";
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("c:/windows/system32/ping.exe " + ip);
while (!oExec.StdOut.AtEndOfStream)
{
input += oExec.StdOut.ReadLine() + "<br />";
}
return input;
}
Is this what was asked for, or am i missing something?
just replace
file_get_contents
with
$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) {
echo "no!";
}
else{
echo "yes!";
}
It might be a lot easier than all that. If you want your page to load then check on the availability or content of some foreign page to trigger other web page activity, you could do it using only javascript and php like this.
yourpage.php
<?php
if (isset($_GET['urlget'])){
if ($_GET['urlget']!=''){
$foreignpage= file_get_contents('http://www.foreignpage.html');
// you could also use curl for more fancy internet queries or if http wrappers aren't active in your php.ini
// parse $foreignpage for data that indicates your page should proceed
echo $foreignpage; // or a portion of it as you parsed
exit(); // this is very important otherwise you'll get the contents of your own page returned back to you on each call
}
}
?>
<html>
mypage html content
...
<script>
var stopmelater= setInterval("getforeignurl('?urlget=doesntmatter')", 2000);
function getforeignurl(url){
var handle= browserspec();
handle.open('GET', url, false);
handle.send();
var returnedPageContents= handle.responseText;
// parse page contents for what your looking and trigger javascript events accordingly.
// use handle.open('GET', url, true) to allow javascript to continue executing. must provide a callback function to accept the page contents with handle.onreadystatechange()
}
function browserspec(){
if (window.XMLHttpRequest){
return new XMLHttpRequest();
}else{
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
</script>
That should do it.
The triggered javascript should include clearInterval(stopmelater)
Let me know if that works for you
Jerry
You could try using PHP in your web page...something like this:
<html><body>
<form method="post" name="pingform" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<h1>Host to ping:</h1>
<input type="text" name="tgt_host" value='<?php echo $_POST['tgt_host']; ?>'><br>
<input type="submit" name="submit" value="Submit" >
</form></body>
</html>
<?php
$tgt_host = $_POST['tgt_host'];
$output = shell_exec('ping -c 10 '. $tgt_host.');
echo "<html><body style=\"background-color:#0080c0\">
<script type=\"text/javascript\" language=\"javascript\">alert(\"Ping Results: " . $output . ".\");</script>
</body></html>";
?>
This is not tested so it may have typos etc...but I am confident it would work. Could be improved too...
I'm trying to use server-side events (SSE) in Javascript and Node.JS to push updates to a web client.
To keep things simple, I have a function which will generate the time every second:
setTimeout(function time() {
sendEvent('time', + new Date);
setTimeout(time, uptimeTimeout);
}, 1000);
The sendEvent function puts together the event in the expected format and sends it to the client.
var clientRes;
var lastMessageId = 0;
function sendEvent(event, message) {
message = JSON.stringify(message);
++lastMessageId;
sendSSE(clientRes, lastMessageId, event, message);
}
The clientRes value comes from the server function to handle the route from the base URL.
app.use('/', function (req, res) {
clientRes = res;
...
}
What I want to achieve at the client UI is a simple page which shows:
> <h1>The current time is {event.data}</h1>
where I derive the current time from the latest message data received from the server.
I have created an index.html file to have the client listen for these server-sent messages:
<!DOCTYPE html>
<html>
<body>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
console.log("Event source is supported");
var source = new EventSource("localhost:3000");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += "=>" + event.data + "<br>";
};
} else {
console.log("Event source not supported");
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
evtSource.addEventListener("time", function(event) {
const newElement = document.createElement("li");
const time = JSON.parse(event.data).time;
console.log("Time listener found time " + time);
newElement.innerHTML = "ping at " + time;
eventList.appendChild(newElement);
});
</script>
</body>
</html>
If I respond to a GET request with this index.html, I don't see any of the time messages.
That is, this server code does not work:
app.use("/", function(request, response) {
response.sendFile(__dirname + "/index.html");
clientRes = response;
});
However if I don't respond with the index.html file and allow the server to push timestamps to the client, they to show up in the browser:
event: time
id: 104
data: 1587943717153
event: time
id: 105
data: 1587943727161
...
Here's is where I'm stuck.
It appears I have successfully gotten the server to push new timestamps every second.
And the browser is seeing them and displaying the text.
But the arrival of the message from the server is not triggering the listener and the message is not being rendered based on the index.html.
Most of the examples I've seen for use of SSE involves a PHP data source. I need for the server to both generate the data and to provide the HTML to display it.
I've been successful in one or the other, but not both at the same time.
I figured out what I was missing.
I did not specify the endpoints correctly.
For the root endpoint, the server code needs to deliver the index.html file.
app.use("/", function(request, response) {
console.log("In root handler");
response.sendFile(__dirname + "/index.html");
});
Index.html contains the script that creates the event source:
var source = new EventSource("http://localhost:3000/time");
But the URL that gets passed in as the input to the EventSource constructor must be a different endpoint (not root). It needs to be the endpoint that generates the timestamps.
So in the server, the handler for the /time endpoint is the one which pushes the data.
app.use('/time', function (req, res) {
res.writeHead(200, {
'content-type': 'text/event-stream',
'cache-control': 'no-cache',
'connection': 'keep-alive'
});
// Save the response
clientRes = res;
});
I everyone, I want to know how to upload a File in HTML5, without Input file, or at least without clicking on it. If there is a way to put it in without clicks and searching fo it, I would like to hear about it.
The thing is, in HTML5 I have a table, when is clicked it opens a modal with info, that info is sent by AJAX to a .jsp file, where I create a PDF using the info, in a certain path. I want to use the same file to upload it with a WCF service, but all what I could do was to create it, and then to look for it with an input file, but I want to use it with out the input file.
Here is some of my code...
The JSP File where I create the PDF file:
<%
String idP = request.getParameter("idP");
String nombreP = request.getParameter("NombreP");
String nombreC = request.getParameter("NombreC");
String presupuesto = request.getParameter("Presupuesto");
String avance = request.getParameter("Avacne");
String empleado = request.getParameter("Empleado");
String constructora = request.getParameter("Constructora");
String idC = request.getParameter("idC");
String idE = request.getParameter("idE");
String idT = request.getParameter("idT");
Font GreenFont = FontFactory.getFont(FontFactory.COURIER, 14, Font.BOLD, new CMYKColor(0, 0, 255, 0));
Font yellowFont = FontFactory.getFont(FontFactory.COURIER, 14, Font.BOLD, new CMYKColor(255, 0, 255, 0));
String path = "E:" + File.separator + "Reportes" + File.separator + "Reporte " + nombreP + ".pdf";
Document document = new Document();
File file = new File(path);
try {
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file.getPath()));
document.open();
Paragraph chapterTitle = new Paragraph(nombreP, yellowFont);
Chapter chapter1 = new Chapter(chapterTitle, 1);
chapter1.setNumberDepth(0);
document.add(chapter1);
document.add(new Paragraph("Nombre cliente:" + nombreC));
document.add(new Paragraph("Presupuesto: $" + presupuesto));
document.add(new Paragraph("Avance del proyecto: %" + avance));
document.add(new Paragraph("Nombre del empleado: " + empleado));
document.add(new Paragraph("Constructora: " + constructora));
document.add(new Paragraph("Id_Proyecto: " + idP));
document.add(new Paragraph("Id_Constructora: " + idC));
document.add(new Paragraph("Id_Empleado: " + idE));
document.add(new Paragraph("Id_Tipo: " + idT));
document.addAuthor("Erick Adahir");
document.addCreationDate();
document.addCreator("LorCyC");
document.addTitle("AVAVAGO");
document.addSubject("Un simple ejemplo");
document.close();
writer.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
%>
The function that calls the JSP:
function agregarEventoDoubleClickEnTablaProyecto()
{
$('#tablaProyecto td').dblclick(function ()
{
var $this = $(this);
var row = $this.closest("tr"); //Hacemos referencia al registro padre de la celda
//alert(row.find('td:eq(0)').text());
//row.find('td:firs').text();
alert("PDF");
$.ajax({
url: "Proyecto/creaPDF.jsp",
data: {
idP: id,
NombreP: row.find('td:eq(1)').text(),
NombreC: row.find('td:eq(2)').text(),
Presupuesto: row.find('td:eq(3)').text(),
Avance: row.find('td:eq(4)').text(),
Tipo: row.find('td:eq(5)').text(),
Empleado: row.find('td:eq(6)').text(),
Constructora: row.find('td:eq(7)').text(),
idC: row.find('td:eq(8)').text(),
idE: row.find('td:eq(9)').text(),
idT: row.find('td:eq(10)').text()
}
}).done(function (data) {
alert("nice...");
});
$('#areaDatosProyecto').modal({
show: 'true'
});
});
}
And finally, the function that uploads the File using Input File:
function subir() {
var archivo = document.getElementById("btnFile").files[0];
alert(archivo);
var fr = new FileReader();
fr.onload = function () {
var bString = this.result;
var objUp = {
elemento: {
NombreOriginal: "nombre",
Documento: bString.split("base64,")[1]
}
};
$.ajax({
url: "http://localhost:84/Uploader/ServicioUploader.svc/ArchivarDocumento",
data: JSON.stringify(objUp),
dataType: "json",
type: "POST",
contentType: "application/json; charset=UTF-8",
success: function (data) {
var id = data.d;
alert(id);
},
error: function (xnr, status, error) {
alert("XNR: " + xnr + ", STATUS: " + status + ", ERROR: " + error);
}
});
};
fr.readAsDataURL(archivo);
}
Hope someone can lend me a hand! Thanks!
You are creating the file inside a JSP.
Which means that it should be created on the path (E:/Reportes/Reporte/[your filename].pdf) where your server is hosted.
You can write the code for upload right there in your JSP itself (where the file object is being created).
I dont see a point of two AJAX calls.
I am not 100% sure I understand what you're trying to do, but If I am understanding your issue correctly, it sounds like you are creating this PDF "server side" on your own system, and saving it to disk, and then on the same system loading up a "client side" web app where you have an upload control (i.e. file selector) where the user selects the PDF that is then uploaded to another server, but you are trying to avoid needing the user to manually select the file to upload in the final step.
If this is your case, unfortunately you cannot do that because it is a security risk, any modern browser will not allow you to programmatically upload a file from a user's hard drive without their manual selection of the file.
SO, not to try and be negative, but it sounds like you may be going about this the wrong way. Why don't you create AND upload the PDF from your server-side (JSP) code? It seems like adding in the client-side web app here is unnecessary. Since you already know WHERE to send the PDF (your URL looks hard-coded there) and you apparently control the server side code, it seems the simplest solution would be to just open an HTTPUrlConnection (or use whatever library you may like) to send the raw bytes of the PDF to it's final destination.
I have a web page that allows users to complete quizzes. These quizzes use JavaScript to populate original questions each time it is run.
Disclaimer: JS Noob alert.
After the questions are completed, the user is given a final score via this function:
function CheckFinished(){
var FB = '';
var AllDone = true;
for (var QNum=0; QNum<State.length; QNum++){
if (State[QNum] != null){
if (State[QNum][0] < 0){
AllDone = false;
}
}
}
if (AllDone == true){
//Report final score and submit if necessary
NewScore();
CalculateOverallScore();
CalculateGrade();
FB = YourScoreIs + ' ' + RealScore + '%. (' + Grade + ')';
if (ShowCorrectFirstTime == true){
var CFT = 0;
for (QNum=0; QNum<State.length; QNum++){
if (State[QNum] != null){
if (State[QNum][0] >= 1){
CFT++;
}
}
}
FB += '<br />' + CorrectFirstTime + ' ' + CFT + '/' + QsToShow;
}
All the Javascript here is pre-coded so I am trying my best to hack it. I am however struggling to work out how to pass the variable RealScore to a MySql database via PHP.
There are similar questions here on stackoverflow but none seem to help me.
By the looks of it AJAX seems to hold the answer, but how do I implement this into my JS code?
RealScore is only given a value after the quiz is complete, so my question is how do I go about posting this value to php, and beyond to update a field for a particular user in my database on completion of the quiz?
Thank you in advance for any help, and if you require any more info just let me know!
Storing data using AJAX (without JQuery)
What you are trying to do can pose a series of security vulnerabilities, it is important that you research ways to control and catch these if you care about your web application's security. These security flaws are outside the scope of this tutorial.
Requirements:
You will need your MySQL database table to have the fields "username" and "score"
What we are doing is writing two scripts, one in PHP and one in JavaScript (JS). The JS script will define a function that you can use to call the PHP script dynamically, and then react according to it's response.
The PHP script simply attempts to insert data into the database via $_POST.
To send the data to the database via AJAX, you need to call the Ajax() function, and the following is the usage of the funciton:
// JavaScript variable declarations
myUsername = "ReeceComo123";
myScriptLocation = "scripts/ajax.php";
myOutputLocation = getElementById("htmlObject");
// Call the function
Ajax(myOutputLocation, myScriptLocation, myUsername, RealScore);
So, without further ado...
JavaScript file:
/**
* outputLocation - any HTML object that can hold innerHTML (span, div, p)
* PHPScript - the URL of the PHP Ajax script
* username & score - the respective variables
*/
function Ajax(outputLocation, PHPScript, username, score) {
// Define AJAX Request
var ajaxReq = new XMLHttpRequest();
// Define how AJAX handles the response
ajaxReq.onreadystatechange=function(){
if (ajaxReq.readyState==4 && xml.status==200) {
// Send the response to the object outputLocation
document.getElementById(outputLocation).innerHTML = ajaxReq.responseText;
}
};
// Send Data to PHP script
ajaxReq.open("POST",PHPScript,true);
ajaxReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ajaxReq.send("username="username);
ajaxReq.send("score="score);
}
PHP file (you will need to fill in the MYSQL login data):
<?php
// MYSQL login data
DEFINE(MYSQL_host, 'localhost');
DEFINE(MYSQL_db, 'myDatabase');
DEFINE(MYSQL_user, 'mySQLuser');
DEFINE(MYSQL_pass, 'password123');
// If data in ajax request exists
if(isset($_POST["username"]) && isset($_POST["score"])) {
// Set data
$myUsername = $_POST["username"];
$myScore = intval($_POST["score"]);
} else
// Or else kill the script
die('Invalid AJAX request.');
// Set up the MySQL connection
$con = mysqli_connect(MYSQL_host,MYSQL_user,MYSQL_pass,MYSQL_db);
// Kill the page if no connection could be made
if (!$con) die('Could not connect: ' . mysqli_error($con));
// Prepare the SQL Query
$sql_query="INSERT INTO ".TABLE_NAME." (username, score)";
$sql_query.="VALUES ($myUsername, $myScore);";
// Run the Query
if(mysqli_query($con,$sql))
echo "Score Saved!"; // Return 0 if true
else
echo "Error Saving Score!"; // Return 1 if false
mysqli_close($con);
?>
I use these function for ajax without JQuery its just a javascript function doesnt work in IE6 or below. call this function with the right parameters and it should work.
//div = the div id where feedback will be displayed via echo.
//url = the location of your php script
//score = your score.
function Ajax(div, URL, score){
var xml = new XMLHttpRequest(); //sets xmlrequest
xml.onreadystatechange=function(){
if (xml.readyState==4 && xml.status==200){
document.getElementById(div).innerHTML=xml.responseText;//sets div
}
};
xml.open("POST",URL,true); //sets php url
xml.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xml.send("score="score); //sends data via post
}
//Your PHP-script needs this.
$score = $_POST["score"]; //obtains score from POST.
//save your score here
echo "score saved"; //this will be displayed in the div set for feedback.
so call the javascript function with the right inputs, a div id, the url to your php script and the score. Then it will send the data to the back end, and you can send back some feedback to the user via echo.
Call simple a Script with the parameter score.
"savescore.php?score=" + RealScore
in PHP Side you save it
$score = isset ($_GET['score']) ? (int)$_GET['score'] : 0;
$db->Query('INSERT INTO ... ' . $score . ' ...');
You could call the URL via Ajax or hidden Iframe.
Example for Ajax
var request = $.ajax({
url: "/savescore.php?score=" + RealScore,
type: "GET"
});
request.done(function(msg) {
alert("Save successfull");
});
request.fail(function(jqXHR, textStatus) {
alert("Error on Saving");
});
I want to reload an image on a page if it has been updated on the server. In other questions it has been suggested to do something like
newImage.src = "http://localhost/image.jpg?" + new Date().getTime();
to force the image to be re-loaded, but that means that it will get downloaded again even if it really hasn't changed.
Is there any Javascript code that will cause a new request for the same image to be generated with a proper If-Modified-Since header so the image will only be downloaded if it has actually changed?
UPDATE: I'm still confused: if I just request the typical URL, I'll get the locally cached copy. (unless I make the server mark it as not cacheable, but I don't want to do that because the whole idea is to not re-download it unless it really changes.) if I change the URL, I'll always re-download, because the point of the new URL is to break the cache. So how do I get the in-between behavior I want, i.e. download the file only if it doesn't match the locally cached copy?
Javascript can't listen for an event on the server. Instead, you could employ some form of long-polling, or sequential calls to the server to see if the image has been changed.
You should have a look at the xhr.setRequestHeader() method. It's a method of any XMLHttpRequest object, and can be used to set headers on your Ajax queries. In jQuery, you can easily add a beforeSend property to your ajax object and set up some headers there.
That being said, caching with Ajax can be tricky. You might want to have a look at this thread on Google Groups, as there's a few issues involved with trying to override a browser's caching mechanisms. You'll need to ensure that your server is returning the proper cache control headers in order to be able to get something like this to work.
One way of doing this is to user server-sent events to have the server push a notification whenever the image has been changed. For this you need a server-side script that will periodically check for the image having been notified. The server-side script below ensures that the server sends an event at least once every (approximately) 60 seconds to prevent timeouts and the client-side HTML handles navigation away from and to the page:
sse.py
#!/usr/bin/env python3
import time
import os.path
print("Content-Type: text/event-stream\n\n", end="")
IMG_PATH = 'image.jpg'
modified_time = os.path.getmtime(IMG_PATH)
seconds_since_last_send = 0
while True:
time.sleep(1)
new_modified_time = os.path.getmtime(IMG_PATH)
if new_modified_time != modified_time:
modified_time = new_modified_time
print('data: changed\n\n', end="", flush=True)
seconds_since_last_send = 0
else:
seconds_since_last_send += 1
if seconds_since_last_send == 60:
print('data: keep-alive\n\n', end="", flush=True)
seconds_since_last_send = 0
And then your HTML would include some JavaScript code:
sse.html
<html>
<head>
<meta charset="UTF-8">
<title>Server-sent events demo</title>
</head>
<body>
<img id="img" src="image.jpg">
<script>
const img = document.getElementById('img');
let evtSource = null;
function setup_sse()
{
console.log('Creating new EventSource.');
evtSource = new EventSource('sse.py');
evtSource.onopen = function() {
console.log('Connection to server opened.');
};
// if we navigate away from this page:
window.onbeforeunload = function() {
console.log('Closing connection.');
evtSource.close();
evtSource = null;
};
evtSource.onmessage = function(e) {
if (e.data == 'changed')
img.src = 'image.jpg?version=' + new Date().getTime();
};
evtSource.onerror = function(err) {
console.error("EventSource failed:", err);
};
}
window.onload = function() {
// if we navigate back to this page:
window.onfocus = function() {
if (!evtSource)
setup_sse();
};
setup_sse(); // first time
};
</script>
</body>
</html>
Here am loading an image, tree.png, as binary data dynamically with AJAX and saving the Last-Modified header. Periodically (every 5 second in the code below). I issue another download request sending backup a If-Modified-Since header using the saved last-modified header. I check to see if data has been returned and re-create the image with the data if present:
<!doctype html>
<html>
<head>
<title>Test</title>
<script>
window.onload = function() {
let image = document.getElementById('img');
var lastModified = ''; // 'Sat, 11 Jun 2022 19:15:43 GMT'
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa( binary );
}
function loadImage()
{
var request = new XMLHttpRequest();
request.open("GET", "tree.png", true);
if (lastModified !== '')
request.setRequestHeader("If-Modified-Since", lastModified);
request.responseType = 'arraybuffer';
request.onload = function(/* oEvent */) {
lastModified = request.getResponseHeader('Last-Modified');
var response = request.response;
if (typeof response !== 'undefined' && response.byteLength !== 0) {
var encoded = _arrayBufferToBase64(response);
image.src = 'data:image/png;base64,' + encoded;
}
window.setTimeout(loadImage, 5000);
};
request.send();
}
loadImage();
};
</script>
</head>
<body>
<img id="img">
</body>
</html>
You can write a server side method which just returns last modified date of the image resource,
Then you just use polling to check for the modified date and then reload if modified date is greater than previous modified date.
pseudo code (ASP.NET)
//server side ajax method
[WebMethod]
public static string GetModifiedDate(string resource)
{
string path = HttpContext.Current.Server.MapPath("~" + resource);
FileInfo f = new FileInfo(path);
return f.LastWriteTimeUtc.ToString("yyyy-dd-MMTHH:mm:ss", CultureInfo.InvariantCulture);//2020-05-12T23:50:21
}
var pollingInterval = 5000;
function getPathFromUrl(url) {
return url.split(/[?#]/)[0];
}
function CheckIfChanged() {
$(".img").each(function (i, e) {
var $e = $(e);
var jqxhr = $.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Default.aspx/GetModifiedDate",
data: "{'resource':'" + getPathFromUrl($e.attr("src")) + "'}"
}).done(function (data, textStatus, jqXHR) {
var dt = jqXHR.responseJSON.d;
var dtCurrent = $e.attr("data-lastwrite");
if (dtCurrent) {
var curDate = new Date(dtCurrent);
var dtLastWrite = new Date(dt);
//refresh if modified date is higher than current date
if (dtLastWrite > curDate) {
$e.attr("src", getPathFromUrl($e.attr("src")) + "?d=" + new Date());//fool browser with date querystring to reload image
}
}
$e.attr("data-lastwrite", dt);
});
}).promise().done(function () {
window.setTimeout(CheckIfChanged, pollingInterval);
});
}
$(document).ready(function () {
window.setTimeout(CheckIfChanged, pollingInterval);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="img" src="/img/rick.png" alt="rick" />
If you are going to check whether files has changed on the server you have to make http request from the server for the file time, because there is no other way for your check the file time once page get loaded to the browser.
So that time check script will like
filetimecheck.php
<?php
echo filemtime(string $filename);
?>
Then you can check the file time using your Javascript. BTW I have put jQuery $.get for check the file time.
dusplayimage.php
<img id="badge" src="image.jpg"> />
<script>
var image_time = <?php echo filemtime(string $filename); ?>;
var timerdelay = 5000;
function imageloadFunction(){
$.get("filetimecheck.php", function(data, status){
console.log("Data: " + data + "\nStatus: " + status);
if(image_time < parseInt(data)) {
document.getElementById('yourimage').src = "image.jpg?random="+new Date().getTime();
}
});
setTimeout(imageloadFunction, timerdelay);
}
imageloadFunction();
</script>
You will be using extra call to the server to check the file time which you can't avoid however you can use the time delay to fine-tune the polling time.
Yes, you can customize this behavior. Even with virtually no change to your client code.
So, you will need a ServiceWorker (caniuse 96.59%).
ServiceWorker can proxy your http requests. Also, ServiceWorker has already built-in storage for the cache. If you have not worked with ServiceWorker, then you need to study it in detail.
The idea is the following:
When requesting a picture (in fact, any file), check the cache.
If there is no such picture in the cache, send a request and fill the cache storage with the date of the request and the file.
If the cache contains the required file, then send only the date and path of the file to the special API to the server.
The API returns either the file and modification date at once (if the file was updated), or the response that the file has not changed {"changed": false}.
Then, based on the response, the worker either writes a new file to the cache and resolves the request with the new file, or resolves the request with the old file from the cache.
Here is an example code (not working, but for understanding)
s-worker.js
self.addEventListener('fetch', (event) => {
if (event.request.method !== 'GET') return;
event.respondWith(
(async function () {
const cache = await caches.open('dynamic-v1');
const cachedResponse = await cache.match(event.request);
if (cachedResponse) {
// check if a file on the server has changed
const isChanged = await fetch('...');
if (isChanged) {
// give file, and in the background write to the cache
} else {
// return data
}
return cachedResponse;
} else {
// request data, send from the worker and write to the cache in the background
}
})()
);
});
In any case, look for "ways to cache statics using ServiceWorker" and change the examples for yourself.
WARNING this solution is like taking a hammer to crush a fly
You can use sockets.io to pull information to browser.
In this case you need to monitor image file changes on the server side, and then if change occur emit an event to indicate the file change.
On client (browser) side listen to the event and then then refresh image each time you get the event.
set your image source in a data-src property,
and use javascript to periodicaly set it to the src attribute of that image with a anchor (#) the anchor tag in the url isn't send to the server.
Your webserver (apache / nginx) should respond with a HTTP 304 if the image wasn't changed, or a 200 OK with the new image in the body, if it was
setInterval(function(){
l= document.getElementById('logo');
l.src = l.dataset.src+'#'+ new Date().getTime();
},1000);
<img id="logo" alt="awesome-logo" data-src="https://upload.wikimedia.org/wikipedia/commons/1/11/Test-Logo.svg" />
EDIT
Crhome ignores http cache-control headers, for subsequent image reloads.
but the fetch api woks as expected
fetch('https://upload.wikimedia.org/wikipedia/commons/1/11/Test-Logo.svg', { cache: "no-cache" }).then(console.log);
the no-cache instructs the browser to always revalidate with the server, and if the server responds with 304, use the local cached version.