I have a Java applet.
After user inputs data into the Java applet controls he presses button in Java applet and Java applet performs some calculating and result is a table (for simplicity table can be considered as String[][]).
I want to show new browser window and output this table in it as html <table>.
How can this be done?
Preferred way is to use javascript if needed, but not involving some server side handling.
Well, JavaScript will have to be used to open the window and populate the HTML - this is something the applet simply has no access to.
Luckily, JavaScript can easily call any public methods your Java applet provides. Unfortunately, Java cannot return a String[][] to JavaScript, but it CAN return a String.
So what you can do is have your Java applet return a JSON serialization of your String[][] array. JavaScript can then convert that JSON to a JavaScript array using the JSON.parse function (available on most modern browsers, but there are also libaries available at json.org)
So here's an example of what I am talking about (that works with at least Java 5 and Chrome):
The Applet Code
import java.applet.*;
public class Test extends Applet {
String data[][];
public void init() {
data = new String[5][2];
data[0] = new String[] { "Peter", "Griffin"};
data[1] = new String[] { "Glen", "Quagmire"};
data[2] = new String[] { "Joe", "Something"};
data[3] = new String[] { "Cleveland", "Brown"};
data[4] = new String[] { "Buzz", "Killington"};
}
public String getData() {
return toJSON(data);
}
/* Quick and dirty, you may want to look
* online for a 'complete' converter
*
* This returns [["Peter", "Griffin"], ["Glen", "Quagmire"], ... etc
*/
protected String toJSON(String data[][]) {
int x, y;
String s = "[";
for (y = 0;y < data.length;y += 1) {
s += "[";
for (x = 0;x < data[y].length;x += 1) {
s += "\""+data[y][x].replaceAll("\"","\\\"")+"\"";
if (x < data[y].length-1) {
s += ", ";
}
}
s += "]";
if (y < data.length-1) {
s += ", ";
}
}
s += "]";
return s;
}
}
The JavaScript Code
<html>
<body>
<p><applet id="applet" code="Test"></applet></p>
<input id="button" type="button" value="Click me"/>
<script type="text/javascript">
(function () {
var button = document.getElementById("button"), applet = document.getElementById("applet");
button.onclick = function () {
var html = [], newWindow, data = JSON.parse(applet.getData()), j;
html.push("<table><tr><th>First Name</th><th>Last Name</th></tr>");
for (j = 0;j < data.length;j += 1) {
html.push("<tr><td>"+data[j][0]+"</td><td>"+data[j][1]+"</td></tr>");
}
html.push("</table>");
newWindow = window.open();
newWindow.document.firstChild.innerHTML = html.join("");
};
}());
</script>
Let me know if you need further clarification!
Preferred way is to use javascript if needed, but not involving some server side handling.
If you really must not have any server side interaction, it'll have to be a jQuery hide/show situation.
If you can bear some server side work, do it with an applet collaborating with servlet. The applet won't do the calculation; the servlet will. After it's complete, the servlet adds the result to the output page and redirects the output stream to it.
Related
I have an object store I need to export or download as a .csv file. I have done some searching and I can't seem to find information on this function. Responses that do not utilize IDB are welcome.
Some background: This is part of a project for work, and I dove into this project without prior knowledge of coding whatsoever. I am using a company issued chromebook, so (as far as I know) NPM installs are not available.
App Background: The project is a customer survey operated through a single terminal. That terminal being my chromebook with hopes to move to an ipad if I can successfully download user inputs to .csv file.
What I have so far:
(function leadIDB() {
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB|| window.msIndexedDB;
if (!window.indexedDB) {
alert('indexDB not supported in this browser');
}
let request = window.indexedDB.open("leadDB", 1),
db,
tx,
store,
index;
request.onupgradeneeded = function(e) {
let db = request.result,
store = db.createObjectStore("LeadStore", {keyPath: "leadID", autoIncrement: true});
index = store.createIndex("firstName", "firstName", {unique: false});
};
request.onerror = function(e) {
console.log("There was an error: " + e.target.errorCode);
};
request.onsuccess = function(e) {
db = request.result;
tx = db.transaction("LeadStore", "readwrite");
store = tx.objectStore("LeadStore");
index = store.index("firstName");
db.onerror = function(e) {
console.log("ERROR" + e.target.errorCode);
};
store.put(newLead);
let lead = store.getAll();
lead.onsuccess = function() {
console.log(lead.result);
console.log(lead.result.firstName);
};
tx.oncomplete = function() {
console.log('Item added to LeadDB');
db.close();
};
};
})();
You are on the right track. There are a few more things to do. First, you need to be able to continue processing once you have loaded the data from indexedDB into js memory. Next, you need to generate the CSV file in memory (as a gigantic string). Next, you need to convert the csv string into a File (which implements Blob). Finally, you want to trigger the download of the file.
There are a few ways to do the first step. I am going to use a promise, but you could do this with a callback or whatever you fancy.
function loadData() {
return new Promise((resolve, reject) => {
var openrequest = indexedDB.open(...);
openrequest.onupgradeneeded = ...;
openrequest.onerror = event => reject(event.target.error);
openrequest.onsuccess = event => {
var db = event.target.result;
var txn = db.transaction(...);
var store = txn.objectStore(...);
var loadrequest = store.getAll();
loadrequest.onerror = event => reject(event.target.error);
loadrequest.onsuccess = event => {
var data = event.target.result;
resolve(data);
};
};
});
}
// You could call the function like this for example:
async function foo() {
var data = await loadData();
console.log('loaded the data, loaded %d objects', data.length);
}
Next, you want to convert the data into a csv-formatted string.
// This is not perfect, just an example of getting you closer
function toCSV(data) {
var output = [];
for(var object of data) {
var row = [];
for(var prop in object) {
row.push(to_csv_value(object[prop]));
row.push(',');
}
row.push('\n');
output.push(row.join(''));
}
return output.join('');
}
function to_csv_value(value) {
var output = '"';
output += value.replace('"', '\\"');
return output + '"';
}
// and then to compose it for example:
async function foo() {
var data = await loadData();
var csvstring = toCSV(data);
}
Next, you want to create a file. You can use the Blob constructor to do this. Something like the following:
// Because File implements blob interface, we are effectively creating a file
// by creating a blob
function createCSVFileFromString(string) {
var csv_mime_type = 'text/csv';
return new Blob([string], {type: csv_mime_type});
}
// And again, to compose it:
async function foo() {
var data = await loadData();
var string = toCSV(data);
var blob = createCSVFileFromString(string);
}
The next step is to make the blob downloadable. This can typically be done using the object url strategy. Kind of like the following:
function downloadBlob(blob, filename) {
var anchor = document.createElement('a');
anchor.setAttribute('download', filename);
var url = URL.createObjectURL(blob);
anchor.setAttribute('href', url);
anchor.click();
URL.revokeObjectURL(url);
}
// And finally, to compose it all together
async function loadAndStartDownloadingData() {
var data = await loadData();
var csvstring = toCSV(data);
var blob = createCSVFileFromString(csvstring);
downloadBlob(blob, 'mydata.csv');
}
Then, somewhere in your application, let's say on click of button, you would do something like this. Im using non-async syntax here just for example of using promise in non-await, you want to always be careful to not hide errors.
var button = ...;
button.onclick = function(event) {
// Load the data and trigger the download, and send any problems to console
loadAndStartDownloadingData().catch(console.warn);
};
Note, this doesn't cover inserting the data, but I'm sure you can figure that out.
I have a link that is toggling a Bootstrap Popover:
Toggle Popover
Now on the back end, result.itemId contains a list of countries that I need to display in the popover. I have the popover call, and a for loop to list out all of the countries associated with result.itemId PLUS a console.log that is properly displaying all of the countries in the console, I just don't know how to have them display properly in the popover.
Here's my Javascript:
$(function () {
$('[data-toggle="popover"]').popover({
html: true,
content: function(){
var rights = $(this).data('rights');
var countries = resultsCountries[rights];
for (var i in countries) {
$(".popover-content").append('<span>' + i + ' – ' + countries[i] + '<span/><br/>');
console.log(i, countries[i]);
}
}
})
})
Like I said, in the console, all of the countries that associated with this result.itemId are displaying as they should, so I am able to access the database the countries are stored in, I just don't know how to get them to display in the popover "popover-content".
I should add, that this is dynamic, so depending on the result.itemId, the content of the popover would be different.
Thank you in advance.
You have to return your elements in the content function (by adding spans to the variable on each iteration).
Here is an example:
$(function() {
var resultCountries = ['Germany', 'France', 'Spain'];
$('[data-toggle="popover"]').popover({
html: true,
content: function() {
var result = $();
for (var i in resultCountries) {
result = result.add(('<span>' + i + ' – ' + resultCountries[i] + '<span/><br/>'));
console.log(i, resultCountries[i]);
}
return result;
}
});
});
CODEPEN
So... aside from being told, in so many words "that's just the way it is", I continued to dig, and lo and behold, the answer presented itself.
$(function () {
$('[data-toggle="popover"]').popover({
html: true,
placement: 'auto right',
content: function(){
var rights = $(this).data('rights');
var content = "";
var countries = resultsCountries[rights];
for (var i in countries) {
content += '<span>' + i + ' – ' + countries[i] + '<span/><br/>';
}
return content;
}
})
})
I saw in several other issues where folks wanted to set their content dynamically, they would always have a return at the end, and THAT would populate the popover properly. The append was also an issue. instead, I set a string variable "content", and then simple += more content through the loop.
The result is exactly as desired, the user clicks the link, and the popover appears displaying the countries associated with the result.itemId.
I am working on a news summarizer and one of its requirements is to display a list of article titles dynamically on a webpage using AJAX called from a database. I have been able to successfully configure the datastore(google app engine) and use the AJAX call to display article title. However, there is one big issue here. I am only able to call and show a single title. I want to run the AJAX call inside a loop so that I can display 10 news articles stored in datastore from 1 to 10 using the variable i of the loop as the unique reference.
The AJAX CODE :
function change(element) {
var xmlhttp;
var i = 1;
var param = "category=" + element + "&no=" + i; // This i is the key to my operation.
alert(param); //testing purpose
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
//alert('function()');
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var div = document.getElementById('content');
div.innerHTML = '';
for (i = 1; i <=10; i++) {
var a = document.createElement('a');
a.href = "#";
a.onclick = rem.bind(null, i);
a.innerHTML = '<h2 id="theading'+i+'">'
+ xmlhttp.responseText + '</h2>'; //the title will go here.
div.appendChild(a);
div.appendChild(document.createElement('br'));
}
}
}
xmlhttp.open("POST", "/display?" + param, true);
xmlhttp.send();
}
I also request to suggest JavaScript code and not jquery, as I am unfamiliar with it. These are my humble beginnings.
UPDATE
MY SERVLET CODE:
public class ArticleHandler extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
String category=req.getParameter("category");
String number=req.getParameter("no");
int i = Integer.parseInt(number);
List<EntityArticles> articles = RegisterClass.ofy().load().type(EntityArticles.class).filter("category ",category).list();
out.write(articles); // Is this the correct way to send this list articles ?
}
}
Is this the correct way to send the list ?
10 articles in responseText, you can render html in server code to responseText(loop in server code). And then in ajax sucess you call
var div = document.getElementById('content');
div.innerHTML = xmlhttp.responseText;
I have created a fiddel for you to understand check it. Ajax Example in fiddle
Are you doing post request or get request? I'm asking this because I saw method as "POST" and parameter passed as "GET" by putting it in url. Please correct that part too in your code.
loadXMLDoc=function()
{
var xmlhttp;
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 (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/ahmadfaizalbh/LaH8F/show/",true);
xmlhttp.send();
}
The best choice is to call the ajax one time and get 10 items.
But, if you have no alternative, you can modify the function a little:
function change(element, i){
var xmlhttp;
//var i=1;
var param = "category=" + element + "&no=" + i;
...
}
Call the function this way (10 times as you need):
for(i=1;int <= 10; i++){
change(element, i);
}
UPDATE
To make one time the ajax call, you can do:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
//append html node
//the object is xmlhttp.responseText. The loop will depend if this is json, html objects, string, etc
}
xmlhttp.open("POST", "/display?" + param, true);
xmlhttp.send();
To obtain 10 results you need (necessarily) to modify the server side script or servlet. If you cannot have access to modify the servlet, is impossible to get 10 items in a single ajax call.
I have a .jsp file with JavaScript.
If I click to the OK button, I call a JavaScript method. This method detects an id.
I want to send this id to my servlet. In my servlet I want to get the id with getParameter(id).
I have implemented this on my local machine, and it functions well. If I deploy my source code on the sever, the JavaScript method will be called and the id will be detected, but the method doesn't send a request to my servlet.
<script language="text/javascript">
function removeLink(){
var id='';
var tmpcounter=0;
var check=0;
for (var counter = 0; counter < (document.getElementsByName("inProject[]").length); counter++) {
if (document.getElementsByName("inProject[]")[counter].checked) {
tmpcounter = tmpcounter+1;
}
}
for (var zaehler = 0; zaehler < (document.getElementsByName("inProject[]").length); zaehler++) {
if (document.getElementsByName("inProject[]")[zaehler].checked) {
check++;
if((check == tmpcounter) || (tmpcounter==1)){
id += 'id='+ document.getElementsByName("inProject[]")[zaehler].value;
}else{
id += 'id='+ document.getElementsByName("inProject[]")[zaehler].value +' OR ';
}
}
}
alert(id);
location.href='<%=request.getContextPath()%>/issues?action=uploaddeletelink&wherestatement=' + id;
close();
}
//-->
</script>
And this is my OK button:
<td align='right'><a class='funktion' href='javascript:removeLink();'>OK<IMG src="<%=request.getContextPath()%>/issuedb/system/layout/funktionpfeil.gif" width="14" height="9" border="0"></a></td>
On my server, the function will be called, and the id will be detected. The line of code below, which sends the request to my servlet, doesn't function however.
location.href='<%=request.getContextPath()%>/issues?action=uploaddeletelink&wherestatement=' + id;
Use AJAX as to call servlet. Get the response back from servlet.
var xmlHttpReq = false;
if (window.XMLHttpRequest) {
xmlHttpReq = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlHttpReq.open('POST', strURL, true);
xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlHttpReq.onreadystatechange = function() {
if (xmlHttpReq.readyState == 4) {
alert(xmlHttpReq.responseText)
}
}
xmlHttpReq.send();
Use Jquery ajax for this purpose, this is simple and handy. All you need to do is use jquery plugin.
function removeLink(){
$.ajax({
url: "<%=request.getContextPath()%>/issues?action=uploaddeletelink&wherestatement="+id,
type: "POST",
success: function(data){
//If you want to return anything in jsp.
}
});
}
Hope this helps..
Not entirely sure whether this has a name but basically I have a large HTML page that is generated from results in a db.
So viewing the HTML page (which is a report) in a browser directly does not display all contents immediately but displays what it has and additional HTML is added as the results from the DB are retrieved...
Is there a way I can make an AJAX request to this HTML page and as opposed to waiting until the whole page (report) is ready, I can start processing the response as the HTML report is loaded? Or is there another way of doing it?
Atm I make my AJAX response it just sits there for a minute or two until the HTML page is complete...
If context is of any use: The HTML report is generated by a Java servlet and the page making the AJAX call is a JSP page. Unfortunately I can't very easily break the report up because it is generated by BIRT (Eclipse reporting extension).
Thanks in advance.
Yep all works, if anyone's interested:
client.open("GET", reportUrl, true);
client.onreadystatechange = responseListener;
client.send();
var reportContents = document.getElementById("reportContents");
// Since this could considerably slow browsers for large reports,
// don't edit report contents for every readystate equal to 3.
// Do it every 10.
var batchUpdate = 10;
var responsesSinceUpdate = 0;
// Don't update the whole contents, just add the new stuff
// since the last update.
var currentLengthOfReportHtml = 0;
// Have max recommended length of report before showing warning.
var maxRecommendedReportLength = 500000;
function responseListener()
{
if (this.status == 200)
{
var readyState = this.readyState;
if (readyState == 3 || readyState == 4)
{
var updatePage = false;
if (readyState == 4)
{
updatePage = true;
var loadingDiv = document.getElementById("reportLoading");
loadingDiv.innerHTML = "";
toggleLargeReportWarning(false);
}
else
{
responsesSinceUpdate++;
if (responsesSinceUpdate > batchUpdate)
{
updatePage = true;
responsesSinceUpdate = 0;
}
}
if (updatePage)
{
var reportLength = this.responseText.length;
reportContents.innerHTML += this.responseText.substring(currentLengthOfReportHtml);
currentLengthOfReportHtml = reportLength;
if (reportLength > maxRecommendedReportLength && readyState == 3)
{
toggleLargeReportWarning(true);
}
}
}
}
}