How can show message while processing a javascript function? - javascript

I writing a html page run from file:// (not use webserver)
I want display a message [Loading.....] in div while Page processing create a data
This is my code demo:
before get data i set:
$("#msg").html("Loading.....");
and after get data i set:
$("#msg").html("Done!");
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src=" https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<script type="text/javascript">
function search() {
$("#msg").html("Loading.....");
getData();
$("#msg").html("Done!");
}
function getData() {
var html = "";
for (var i = 0; i < 200000; i++) {
html += i + "<br>";
}
$("#data").html(html);
}
</script>
</head>
<body>
<input type="button" id="btnSearch" value="Search" onclick="search(); return false;" />
<div id="msg">Message</div>
<div id="data"></div>
</body>
</html >
How can show message while processing a javascript function?
i try use ajax:
function search() {
$("#msg").html("Loading.....");
$.ajax({
success: function () {
getData();
$("#msg").html("Done!");
}
});
}
But it occuring error:
Access to XMLHttpRequest at 'file:///C:/Users/dt/Desktop/HTMLPage1.html' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

Actually, there are two problems with this code.
1. Trying to make AJAX request over file:// protocol
That's where you get the error from. Doing this is incorrect because of security of the users.
Imagine, that you visit a random website on the Internet, and it can see all of your files on your computer, without even asking for permission or letting you know what it does. In that case, those who use the Internet could say goodbye to private life!
So, instead:
If this file will be on your server, and you're just testing, then do it on a localhost server.
If you want to let the user grant access to one of his/her files, use a filepicker (<input type="file">).
If you want to access users' files without permission, then... look for alternative solutions (web pages cannot do this).
2. Synchronous data processing
Once you've somehow solved to get the files, your example will work. But you'll be unable to update the display during processing. That's why your first example doesn't work.
It will also don't let other rendering, or asynchronous JS code to run. Usually, this isn't a problem, as long as your code doesn't take long time to execute.
But if it does, you'll need to let some scheduled code to execute, during the processing.
You have 2 options:
Use a Web Worker to do heavy synchronous operations without freezing the site
//your HTML file
<script>
async function search() {
$("#msg").html("Loading.....");
await getData();
$("#msg").html("Done!");
}
function getData() {
return new Promise((rs,rj) => {
const worker = new Worker('./worker.js')
worker.onmessage = rs
worker.onerror = rj
})
.then(data => $("#data").html(data));
}
</script>
//worker.js
var html = "";
for (var i = 0; i < 20000; i++) {
html += i + "<br>";
}
self.postMessage(html)
Put setTimeout(..., 0) in your processing code to make it asynchronous and the site usable while processing
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src=" https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<script type="text/javascript">
async function search() {
$("#msg").html("Loading.....");
await getData();
$("#msg").html("Done!");
}
async function getData() {
var html = "";
for (var i = 0; i < 20000; i++) {
html += i + "<br>";
if(i % 10 === 0)
//On every 10th iteration, wait some...
await new Promise(rs => setTimeout(rs, 0))
}
$("#data").html(html);
}
</script>
</head>
<body>
<input type="button" id="btnSearch" value="Search" onclick="search(); return false;" />
<div id="msg">Message</div>
<div id="data"></div>
</body>
</html >

Good question!
AJAX and XMLHTTP requests send messages over HTTP Protocol. HTTP is a protocol for sending messages over the internet. You must use a webserver, or at least call to localhost, in order to make a HTTP request from your clientside code.
If you really want to just show a "loading" message, sending your request to localhost will at least allow you to "SEND" your HTTP request. Just know that your request will always fail unless you set up a webserver on localhost to answer it. You could write your "Done!" in an ajax fail function in that case:
$.ajax({
success: function () {
getData();
$("#msg").html("This will never show up until you set up a webserver that you called from localhost");
}
fail: function () {
getData();
$("#msg").html("Done! (This is showing because you called from localhost)!");
}
});

Related

Redirect after processing a POST request in Apps Script

I have had an issue with getting the google scripts page to redirect back towards my custom URL. The script currently executes but I cant get it to redirect back to its previous page after it is finished executing.
Heres the script.gs code:
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
var name= String(mailData.name);
var message= String(mailData.message);
var email= String(mailData.email);
var all= ("Name: "+name+"\nReply address: "+email+"\nMessage: "+message);
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
MailApp.sendEmail({
to: String(sendEmailTo),
subject: String(mailData.subject),
replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
body: String(all)
});
doGet();
return HtmlService.createHtmlOutput('xxxxxxxxxx.com');
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
Here is my HTML code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="2;url=xxxxxxxxxx.com" />
<base target="_top">
</head>
<body>
Click here to go back.
</body>
</html>
What would be the best way to make the script open the index.html page so I could easily redirect back to the custom URL?
Here's a working example of redirecting after processing a POST request.
Code.gs
var REDIRECT_URL = "http://www.stackoverflow.com";
function doPost(e) {
Logger.log("POST request");
Logger.log(e)
return redirect();
}
function doGet() {
Logger.log("GET request");
var template = HtmlService.createTemplateFromFile("form");
template.url = ScriptApp.getService().getUrl();
return template.evaluate();
}
function redirect() {
return HtmlService.createHtmlOutput(
"<script>window.top.location.href=\"" + REDIRECT_URL + "\";</script>"
);
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form action="<?= url ?>" method="post">
<input type="text" name="test_field" value="test data">
<button type="submit">Submit form</button>
</form>
</body>
</html>
Usage
When I visit the published web app (i.e. using a GET request), I'm presented with the simple form.
Submitting that form (i.e. using a POST request), I'm immediately redirected to http://www.stackoverflow.com.
This output is captured in the script log:
[18-06-19 10:39:04:731 PDT] POST request
[18-06-19 10:39:04:732 PDT] {parameter={test_field=test data}, contextPath=, contentLength=20, queryString=, parameters={test_field=[test data]}, postData=FileUpload}
Regarding your code sample, you have:
doGet();
return HtmlService.createHtmlOutput('xxxxxxxxxx.com');
That doesn't make sense as you're not doing anything with the results of doGet(). In order to make the doGet() call useful, replace the above with the following:
return doGet();

Update page content from live PHP and Python output using Ajax

Long-time user, first-time asker. I've learned so much from the community and I love this site.
So here is what I'm shooting for. I want to have a web interface that runs ping commands on the backend. I ideally want a website that has a text input that allows you to enter an IP address or domain, a button that runs the command and a python script that runs from PHP to actually run the ping command. The tricky part for was to get the output to print to the website live as it is outputted on the command line. I want to do it this way as a way to future-proof the concept and eventually use different iperf parameters.
I built a little PHP page that "technically" gets the job done but I can't figure out how to only call the PHP script when the button is clicked. Since it's a PHP page, it runs whenever the page is loaded. So after some research, I figure ajax jquery is what I'm looking for. I've spent about 2 days trying different things that get me really close but it seems that I'm dancing around my solution.
From what I've learned about ajax, I essentially need a button that runs an ajax function that is linked to my working php script. I can get it to run the script but I can't get it to update the page content in a live/continuous manner. Only when the command is finished running.
Here is my php page that does what it needs to do but does it everytime the page is loaded/reloaded. Not ideal. I want the script to only run when the button is pressed.
liveping.php:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<form action="liveping.php" id="ping" method="post" name="ping">
Domain/IP Address: <input name="domain" type="text"> <input name="ping" type="submit" value="Ping">
</form><?php
if (isset($_POST['ping'])) {
function liveExecuteCommand($cmd)
{
while (# ob_end_flush()); // end all output buffers if any
$proc = popen("$cmd 2>&1", 'r');
$live_output = "";
$complete_output = "";
while (!feof($proc))
{
$live_output = fread($proc, 4096);
$complete_output = $complete_output . $live_output;
echo "<pre>$live_output</pre>";
# flush();
}
pclose($proc);
}
}
$domain = $_POST['domain'];
$pingCmd = "python /var/www/html/ping.py ".$domain;
if (isset($_POST['ping'])) {
liveExecuteCommand($pingCmd);
}
?>
</body>
</html>
ping.py:
#!/usr/bin/python
import cgi
import os
import sys
ping = "ping -c 5 -W 2 "+sys.argv[1]
os.system(ping)
Some things I've tried:
<html>
<head>
<script>
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = setInterval(function() {
if (ajax.readyState == 4) {
document.getElementById('content').innerHTML = ajax.responseText;
}
},100);
function updateText() {
ajax.open('GET', 'ajax.php');
ajax.send();
}
</script>
</head>
<body>
<button onclick="updateText()">Click Me</button>
<div id="content">Nothing here yet.</div>
</body>
</html>
OR
<!DOCTYPE html>
<html>
<body>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script type="text/javascript">
var auto_refresh = setInterval(
function ()
{
$('#load_tweets').load('ajax.php').fadeIn("slow");
}, 1000); // refresh every 10000 milliseconds
</script>
</head>
<div id="load_tweets"> </div>
</body>
</html>
WITH ajax.php
<?php
while (# ob_end_flush()); // end all output buffers if any
$proc = popen("ping -c 5 -W 2 google.com", 'r');
$live_output = "";
$complete_output = "";
while (!feof($proc))
{
$live_output = fread($proc, 4096);
$complete_output = $complete_output . $live_output;
echo "<pre>$live_output</pre>";
# flush();
}
pclose($proc);
?>
Thanks for any help!
You do not need python for showing ping results. Just two PHP files will be enough.
index.php will have the AJAX functionalities along with the form.
ajax.php will have the code to ping specified domain address.
I afraid that using jQuery you might not able to catch the live feed. Because it doesn't have any onreadystatechange. So, you might need to use vanilla JavaScript in this case. Here is a working demonstration:
index.php:
<!DOCTYPE html>
<html>
<head>
<title>Ping AJAX</title>
</head>
<body>
<div>
Domain/IP Address: <input id="domain" type="text">
<input id="ping" type="button" value="Ping">
</div>
<div id="result"></div>
<script>
function updateText(domain) {
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function() {
if (this.readyState == 3) {
var old_value = document.getElementById("result").innerHTML;
document.getElementById("result").innerHTML = this.responseText;
}
};
var url = 'ajax.php?domain='+domain;
ajax.open('GET', url,true);
ajax.send();
}
document.getElementById("ping").onclick = function(){
domain = document.getElementById("domain").value;
updateText(domain);
}
</script>
</body>
</html>
ajax.php:
<?php
if (isset($_GET['domain'])) {
function liveExecuteCommand($cmd)
{
while (# ob_end_flush()); // end all output buffers if any
$proc = popen($cmd, 'r');
$live_output = "";
$complete_output = "";
while (!feof($proc))
{
$live_output = fread($proc, 4096);
$complete_output = $complete_output . $live_output;
echo "<pre>$live_output</pre>";
# flush();
}
pclose($proc);
}
$domain = $_GET['domain'];
$pingCmd = "ping ".$domain;
liveExecuteCommand($pingCmd);
}
else{
echo "No post request";
}
?>
Output:
Declaimer:
The ping command is changed as I am currently using Windows operating system. Update it according to your operating system.
As a first time questioner, you have described the problem neatly and also showed your efforts to solve the problem. I really appreciate it.
ajax.readyState == 4
essentially means, script on the other side has finished ... 3 is partial.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
You just have to take all ajax script into the function
example:
function updateText() {
$.ajax({
type: 'GET', // can be POST, too
url: "ajax.php",
crossDomain: true,
data: {
firstvar: firstvar,
secondvar: secondvar
},
cache: false,
success: function(data) {
if($.trim(data) == "false") {
alert("Fail to recived data");
}
else {
// Success getting data
// Do some jobs
}
}
});
}
If you want to cancel submit to not refesh, U can use
return false; // At the end of the function above
Hope it helps.

Customize DocxJS to render local docx file

I just found a working docx to html converter using only javascript on github. The main code which converts docx to html is below. The issue is the page just has a button which on click or drag and choosing a word document, opens it as html. I want to specify a file location in the code so I can load it on the server for loading some documents from computer locally.
Code which converts docx to html and renders :
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DocxJS Example</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript" src="https://www.docxjs.com/js/build/latest.docxjs.min.js"></script>
</head>
<body>
<input id="inputFiles" type="file" name="files[]" multiple="false">
<div id="loaded-layout" style="width:100%;height:800px;"></div>
<script>
$(document).ready(function(){
var $inputFiles = $('#inputFiles');
$inputFiles.on('change', function (e) {
var files = e.target.files;
var docxJS = new DocxJS();
docxJS.parse(
files[0],
function () {
docxJS.render($('#loaded-layout')[0], function (result) {
if (result.isError) {
console.log(result.msg);
} else {
console.log("Success Render");
}
});
}, function (e) {
console.log("Error!", e);
}
);
});
});
</script>
</body>
</html>
I tried changing var files = e.target.files; to var files = "C:/sda/path/to/docx"; but that didn't help.
I tried to change
var files = e.target.files;
to
var files = new Array(new File([""], "sample.docx"));
but it gives me OOXML parse error.
Update:
Lets say I have a file location variable in PHP and I wish to use that instead in the javascript code. How do I do it?
I also checked docx2html javascript code and here is the code for it:
<!DOCTYPE html>
<html>
<head>
<script src="index.js"></script>
<script>
function test(input){
require("docx2html")(input.files[0]).then(function(converted){
text.value=converted.toString()
})
}
</script>
</head>
<body>
<input type="file" style="position:absolute;top:0" onchange="test(this)">
<br/>
<br/>
<textarea id="text"></textarea>
</body>
</html>
Same issue need input.files[0] here as well
Update:
I am trying to use the method mentioned in the comments but encounter some errors:
var fil;
var getFileBlob = function (url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function (blob) {
cb(blobToFile(blob, 'test.docx'));
});
};
getFileObject('demo.docx', function (fileObject) {
console.log(fileObject);
fil = fileObject;
});
The error primarily was “Cross origin requests are only supported for HTTP.” before I used https://calibre-ebook.com/downloads/demos/demo.docx instead of just demo.docx in above file path. This however gives another error:
Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
which means chrome cannot load it. It needs to be working on a server. If someone can help providing a fix to make it work offline, let me know. The last method was asynchronous call.
In the browser, there is a sandbox policy.
It can not access files directly via Path.
Please access the file through drag & drop event or input file change event.

YouTube API -- extracting title and videoId attributes to build hyperlink

The following is a JavaScript file that searches through YouTube video data using its API. Down at the bottom you'll see the onSearchResponse() function, which calls showResponse(), which in turn displays the search results.
As this code from Codecademy stands, a HUGE amount of information gets printed relating to my search term.
Instead of all that, can I simply display a hyperlink using the title and videoId attributes? How would I go about altering responseString in showResponse() to build that link? Thank you!
// Your use of the YouTube API must comply with the Terms of Service:
// https://developers.google.com/youtube/terms
// Helper function to display JavaScript value on HTML page.
function showResponse(response) {
var responseString = JSON.stringify(response, '', 2);
document.getElementById('response').innerHTML += responseString;
}
// Called automatically when JavaScript client library is loaded.
function onClientLoad() {
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
}
// Called automatically when YouTube API interface is loaded (see line 9).
function onYouTubeApiLoad() {
// This API key is intended for use only in this lesson.
// See link to get a key for your own applications.
gapi.client.setApiKey('AIzaSyCR5In4DZaTP6IEZQ0r1JceuvluJRzQNLE');
search();
}
function search() {
// Use the JavaScript client library to create a search.list() API call.
var request = gapi.client.youtube.search.list({
part: 'snippet',
q: 'clapton'
});
// Send the request to the API server,
// and invoke onSearchRepsonse() with the response.
request.execute(onSearchResponse);
}
// Called automatically with the response of the YouTube API request.
function onSearchResponse(response) {
showResponse(response);
console.log(response);
}
Here is the corresponding HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="stylesheets/styles.css">
<meta charset="UTF-8">
<title>My YouTube API Demo</title>
</head>
<body>
<section>
<div id="response"></div>
</section>
<script src="javascripts/search-2.js"></script>
<script src="https://apis.google.com/js/client.js?onload=onClientLoad" type="text/javascript"></script>
</body>
</html>
Your advice is much appreciated!
I think it might be what you are exactly trying to do.
function showResponse(response) {
var html = response.items.map(itemToHtml);
document.getElementById('response').innerHTML += html;
}
function itemToHtml(item) {
var title = item.snippet.title;
var vid = item.id.videoId;
return generateHyperlink(title, vid);
}
function generateHyperlink(title, vid) {
return '' + title + '<br/>';
}
This code show up links named title having YouTube video link using videoId.

Performing 2 successive tasks when a HTML form is submitted (using Ajax and a server made with Express in Node.js)

I have an input form in a HTML file:
<form id="urlarticle">
<input type='text' name='thislink'>
<input type='submit' value='Select'>
</form>
I want, when the submit button is clicked, 2 things to happen, in this order:
TASK 1: Make a POST request to a server, in order to enter new data in a database. Actually it is already working with the following code on the front-end:
<script type='application/javascript'>
$("#urlarticle").submit(function() {
$.ajax({
type: "POST",
url: "/selection/yes",
data: $("#urlarticle").serialize(),
success: function(data)
{alert(data);
}
});
return false;
});
</script>
...and with the following code on the back-end (server made with Express in Node.js):
app.post('/selection/yes', function(req, res) {
link = req.body.thislink;
// part omitted here: function that do several things and then save some data to a database
});
TASK 2: Open a new window, rendered with an EJS view following a GET request on the server-side. TASK 2 has to be performed after TASK 1, because it uses the data saved in the database by TASK 1.
The code on the front-end should look like this:
<script type='application/javascript'>
$("#urlarticle").submit(function() {
var linkValue = $('input[name="thislink"]').val();
window.open('/selection/yes/?value='+linkValue);
});
</script>
...and the task is ready to be handled on the back-end:
app.get('/selection/yes/', function(req, res) {
var thislink = req.param("value");
// parts omitted here
res.render('selection_form.ejs');
});
});
But how can I make this TASK 2 to be executed only after TASK 1 is done? Thank you for your help!
I've created a sample NodeJS application that uses a lot of the same concepts (using Express and some jQuery on the client-side).
WORKING EXAMPLE: http://runnable.com/U3JEKcrGzPc1V8eQ/promises-w-bluebird-for-node-js-and-express
Using a basic Express application where an initial form is rendered using EJS (this is the GET request on /). Form submissions return a POST request to the same URL and are handled with a 2s delay to simulate a database action.
/**
* Create a global storage variable as a example of an
* attached local database
*/
GLOBAL.linkStorage = [];
app.route('/')
.post(function(req, res){
console.log("Submission: " + req.body);
GLOBAL.linkStorage.push(req.body.link);
renderDelayedResponse(res);
})
.get(function(req, res){
res.render('form.ejs');
});
app.route('/2')
.get(function(req, res) {
// No need to pass in GLOBAL.linkValue since it's checked automatically
res.render('submission.ejs');
});
/**
* Delay the response by a few seconds to simulate a database
* create/update action
*/
function renderDelayedResponse(respWriter) {
setTimeout(function() {
GLOBAL.viewCount++;
respWriter.send('Action Completed');
}, 2000);
}
There are going to be problems with calling window.open() after an asynchronous action, the popup blocker fires in all cases through my tests. To workaround this, you can see that the example has an embedded IFRAME that refreshes (after the 2 second database save completes) and displays the submitted value.
The complexity is mostly handled through jQuery where the IFRAME refresh occurs after we know that the POST request has submitted:
<!doctype html>
<html>
<head>
<style>
.busy {
cursor: wait !important;
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery-git.js"></script>
<script type="text/javascript">
$('document').ready(function () {
function refreshViewer() {
window.open("/2", "viewer");
document.getElementById('submissionFrame').contentWindow.location.reload(true);
}
$('form input#submitLink').on('click', function () {
var linkValue = $('input#link').serialize();
$('body').addClass('busy');
$.post('/', linkValue)
.done(function(data) {
$('body').removeClass('busy');
$('input#link').val('');
refreshViewer();
});
return false;
});
});
</script>
</head>
<body>
<div class="container">
<form id="urlarticle" method="POST">
<input type="text" name="link" placeholder="Link" id="link" />
<input type="button" value="Submit" id="submitLink" />
</form>
<iframe id="submissionFrame" src="/2" seamless="seamless" width="50%" style="margin-top:100px">
</iframe>
</div>
</body>
</html>

Categories

Resources