Express JS render view with received image - javascript

I am working with two Express JS applications one is an API and second is application that is using this API by making requests and displaying received informations to user.
In API route I'm sending image as response:
router.get('/:customer_id',authController.isAuthenticated,(req,res) => {
.
. Retrieving customer data
.
return res.sendFile('/uploads/'+foundCustomer.doc_path);
});
And later another application is getting this document:
router.get('/:customer_id',(req,res) => {
var options = {
url: 'http://'+config.API.user+':'+config.API.password+'#'+config.API.host+':'+config.API.port+'/customers/'+req.params.customer_id
};
request(options,(err,response,body)=>{
return res.render('customer/show',{
document: ?, // Send document as parameter to view
});
});
});
In this point I want to render customer/show(EJS view engine) with customer document, but I don't want to save this document in my application files, because document is only needed to display in view (customer details and document are stored in another application).
I was trying to create temporary directory in my application structure, but it is difficult to manage deleting those not needed documents (Application has many users and at the same time many customers can be displayed).
Another solution that I was trying to implement is to make Ajax request on client side and latter append received document to <object data='document'>. But this request has to be authenticated with user and password, so I realised that storing credentials on client side javascript is not the best idea...
I am not sure that is it even possible to render and display image without saving in application files?
I would be grateful for any help, maybe the best workaround is to somehow manage temporarily saved documents.

Why not create a File object inside EJS template then use that for src attribute on an <img> ? You're already getting the raw buffer/blob from your image API server. Store it inside template.

From https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
// place this code (store this variable) inside of your EJS template
// so it can be used by the client-side JS
var aBlob = new Blob( array[, options]); // Where array is the raw buffer data returned from your image API server
See https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
var objectURL = URL.createObjectURL( aBlob ); // Where object is a Blob object
See https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
const img = document.createElement('img');
img.src = objectURL;

Final solution (tested), using axios to make API request:
In my route I'm going to make HTTP request to my API to retrieve PDF file(document):
axios.get(`http://my-api/customer/id`).then(response => {
var photo = new Buffer(response.data, 'binary').toString('base64');
return res.render('customers/show',{
document: document
});
});
In my ejs view, I'm using HTML object tag to display received PDF:
<object data="data:application/pdf;base64,<%-document%>"></object>

Related

How to Update HTML using Node JS from MYSQL

Question
How can i change my HTML data in the files via node JS i am not using EJS or any view engine I have a views folders where all the files are .js files returning HTML how can i change the data from the node server which selects the MYSQL data for example if i have
I have tried using res.send but it changes the whole file how can i change for example on the about page /aboutus
<h1 id='name'></h1>
How can i add data from the server to edit that file?
thanks
For those who can't quite understand what i am saying is i have a server side which is meant to retrieve an html name for example david and i have a views folder containing js files like home.js which returns html value to the index.html file i want to change the heading tag in html like the code above i want 'David' to be put in the h1 tag
I have not been able to understand perfectly what you want to do ...
But I believe that in any case to create a dynamic client server infrastructure you could use two methods:
by creating an endpoint that returns the data in json or xml format from the database, and replacing your DOM elements with the real data
example:
Express Backend example
app.get('/api/user', async function(req, res) {
const userdata = await getUserData()
res.send(JSON.stringify(userdata));
});
Front end example:
fetch('http://MYAPI.com/api/user')
.then(response => response.json())
.then(data =>{
document.getElementById("username").innerHTML = data.username;
document.getElementById("email").innerHTML = data.email;
});
by converting your html files into handlebars (for example) and replacing the handlebars tags with real data, then return html ready to be rendered.

Is there a way to Post an array to web api or mvc controller and get a file back to download as a result?

I use an html table where it's content can be changed with mouse drag and drop implemented. Technically, you can move the data from any table cell to another. The table size 50 row * 10 column with each cell given a unique identifier. I want to export it to .xlsx format with C# EPPlus library, and give back the exported file to client.
So I need the pass the whole table data upon a button press and post it to either a web api or an mvc controller, create an excel file (like the original html table data) and send it back to download with browser.
So the idea is to create an array which contains each of table cell's value ( of course there should be empty cells in that array), and post that array to controller.
The problem with that approach lies in the download, if I call the api or mvc controller with regular jquery's ajax.post it did not recognize the response as a file.
C# code after ajax post:
[HttpPost]
public IHttpActionResult PostSavedReportExcel([FromBody]List<SavedReports> savedReports, [FromUri] string dateid)
{
//some excel creation code
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(package.GetAsByteArray()))
};
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = dateid + "_report.xlsx"
};
ResponseMessageResult responseMessageResult = ResponseMessage(response);
return responseMessageResult;
}
Usually, for this kind of result I could use window.location = myurltocontroller to download properly , but that is only for GET requests, POST anything is not possible.
I found some answers which could help me in this topic:
JavaScript post request like a form submit
This points out I should go with creating a form, which passes the values, but I do not know how to do so in case of arrays (the table consists 50*10 = 500 values which I have to pass in the form)
I tried some only frontend solutions to the html-excel export problem, which of course does not require to build files on api side, but free jquery add-ins are deprecated, not customizeable, handle only .xls formats, etc.
I found EPPlus nuget package a highly customizeable tool, that is why I want to try this is at first place.
So the question is: how can I post an array of 500 elements, that the controller will recognize, generate the file, and make it automatically download from browser?
If you can provide some code that would be fantastic, but giving me the right direction is also helpful.
Thank you.
You can use fetch() (docs) to send the request from the JS frontend. When the browser (JS) has received the response, it can then offer its binary content as a download. Something like this:
fetch("http://your-api/convert-to-excel", // Send the POST request to the Backend
{
method:"POST",
body: JSON.stringify(
[[1,2],[3,4]] // Here you can put your matrix
)
})
.then(response => response.blob())
.then(blob => {
// Put the response BLOB into a virtual download from JS
if (navigator.appVersion.toString().indexOf('.NET') > 0) {
window.navigator.msSaveBlob(blob, "my-excel-export.xlsx");
} else {
var a = window.document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = "my-excel-export.xlsx";
a.click();
}});
So the JS part of the browser actually first downloads the file behind the scenes, and only when it's done, it's triggering the "download" from the browsers memory into a file on the HD.
This is a quite common scenario with REST APIs that require bearer token authentication.

Better way of passing Mongodb query data to Pug

I am looking for a better way of passing data to my index.js file in a webdev application. Note I really only have about a month of webdev experience so this is likely due to lack of experience. here is my software flow:
I query data in a route handler before the page is rendered. I then pass this data to the rendered page (note i need to keep some of the key-vals hidden. However aggregation works).
exports.getPlotView = async(req, res, next) =>{
//grab the module to query from, stored as var.testModel
const qParse = new PlotQueryParse(req.query).parseObj();
// console.log(qParse)
// const testblockName = qParse.testblock+"Name" ;
// const limitName = qParse.limitname;
const aggregationObj = {$match:
{'jobId':qParse.jobId, '<key2>':<val2>, "<key>":"<val>"}
}
const data = await qParse.testModel.aggregate([aggregationObj]);
console.log(data[0])
const dataString = JSON.stringify(data[0]);
//parse the url to make the query
res.status(200).render('testPlotView', {
pageHeader: "Test",
subHead: "Test summary",
IPn: "IPn",
inData:dataString
});
}
data is passed to pug template. The template uses this as a hidden element
extends base
block content
div.hide_data #{inData}
div#dataviz
now in my index.js script (listens for evenets), the data is loaded from the page and then stored for post processing. I would like to directly access the variable instead of having it hidden then accessing the DOM element.
window.addEventListener('load', function(){
if(window.location.href.includes('testplotdata')){
console.log('its a me mario')
//if we are in a test plot data page, lets plot
var jsonObject = JSON.parse(document.querySelector('.hide_data').innerHTML);
console.log(jsonObject['testData'])
//post processing code ....
}
})
Again, I want a way to grab my queried data without saving it as a DOM element then accessing it in my external event listener script.
Thanks!
Instead of storing data in HTML, add inline script to your template to store it in a global variable instead. So replace div.hide_data #{inData} with:
script.
var inData = !{inData}; // inData passed by backend must be a string
// representing a valid JS object (JSON will do)
Now you just access inData as a ready native object in your external script (which you need to make sure load after the above script, putting it at the end of <body> will do)
// No need: var jsonObject = JSON.parse(document.querySelector('.hide_data').innerHTML);
console.log(inData); // Go ahead with the data

Change content of file - Alfresco

I have an Custom Document Library Action to Alfresco files, and when I press this button opens a new page with an applet (javascript) to make changes to a file, but I'm doing the modifications in base64 and to "appear" on the screen with this :
var stringPDF = "<object data=\"data:application/pdf;base64," +
JSON.parse(pdfbase64).message + "\"
type=\"application/pdf\"width=\"100%\"
height=\"100%\"></object>";$("#pdfTexto").html(stringPDF);
But I really need is to change the file, for when the repository again, there have to change, not just display. How do I change the existing file's contents to the new with the change?
I use this URL to make GET of the file:
http://localhost:8080/share/proxy/alfresco/slingshot/node/content/workspace/SpacesStore/21384098-19dc-4d3f-bcc1-9fdc647c05dc/latexexemplo.pdf
Then I convert to the base64... And I make the changes...
But if I want to make a POST to change the content, how can I make this?
Thanks in advance.
As I mentionned in my response to this question :
The fastest and easiest way to achieve that is to leverage the RESTfull API
This will also ensure compatibility with new versions of alfresco.
Note that you need to provide the noderef for the document to update in the form property updatenoderef and that the property majorversion is a boolean flag to specify if the new version is a minor/major version of the document.
Here is a sample code that might help you with your usecase:
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost uploadFile = new HttpPost(<alfresco-service-uri>+"/api/upload?alf_ticket="+<al-ticket>);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("username", "<username>", ContentType.TEXT_PLAIN);
builder.addTextBody("updatenoderef", <noderef>, ContentType.TEXT_PLAIN);
builder.addTextBody("...", "...", ContentType.TEXT_PLAIN);
builder.addBinaryBody("filedata", <InputStream>, ContentType.DEFAULT_BINARY, <filename>);
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
CloseableHttpResponse response = httpClient.execute(uploadFile);
String responseString = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
JSONObject responseJson = new JSONObject(responseString);
if (response.getStatusLine().getStatusCode()!=200){
throw new Exception("Couldn't upload file to the repository, webscript response :" + responseString );
}
Note 1: You need to replace these tockens <*> with your own values/vars
Note 2: If you have problem retrieving a ticket, check this link, or this one
Note 3: To do this in JavaScript instead of java, visit this link and try to use js to post the parameters I referred as instructed !
Note 4: Since you are working on share, you are most probably authenticated.
If it is the case, you can access your alfresco repo through the proxy endpoint in share and all requests will have authentication ticket attached to them before getting forwarded to your repo !
In other terms, use this endpoint :
/share/proxy/alfresco/api/upload
Instead of :
/alfresco/service/api/upload
and You won't even have to attach a ticket to your requests.
You need to follow these steps to achieve what you are looking for.
1) Reading File:
To display content of PDF file already uploaded you need to read content of file. You are able to do it successfully using following API call.
http://localhost:8080/share/proxy/alfresco/slingshot/node/content/workspace/SpacesStore/21384098-19dc-4d3f-bcc1-9fdc647c05dc/latexexemplo.pdf
2) Capture New Content:
Capture new file content from User from applet. I guess you are storing it in some String variable.
3) Edit Existing File Content:
Issue here is that you cannot simply edit any pdf file using any of out of box Alfresco REST API (as far as I know). So you need to create your own RESTFul API which could edit pdf file's content. You can consider using some third party libraries to do this job. You need to plugin logic of editing pdf in RESTFul API
4) Changes back to Repo:
Call Your API from Step 3:
You could also have look at this plugins which could fulfill your requirements.
https://addons.alfresco.com/addons/alfresco-pdf-toolkit
Hope this helps.

Piping data from a file to a rendered page in Sails.js

My application needs to read in a large dataset and pipe it to the client to manipulate with D3.js. The problem is, on large datasets, the reading/loading of the file contents could take a while. I want to solve this using streams. However, I'm unsure of how to do so in the context of the Sails framework.
What I want to do is read the contents of the file and pipe it to a rendered page. However, I can't figure out how to pipe it through if I use something like res.view('somePage', { data: thePipedData });.
I currently have something like this:
var datastream = fs.createReadStream(path.resolve(DATASET_EXTRACT_PATH, datatype, dataset, dataset + '.csv'));
datastream.pipe(res);
...
return res.view('analytics', { title: 'Analytics', data: ??? });
What's the best way to approach this?
Based on your example it seems like the best course of action would be to set up a separate endpoint to serve just the data, and include it on the client via a regular <script> tag.
MyDataController.js
getData: function(req, res) {
/* Some code here to determine datatype and dataset based on params */
// Wrap the data in a Javascript string
res.write("var theData = '");
// Open a read stream for the file
var datastream = fs.createReadStream(
path.resolve(DATASET_EXTRACT_PATH, datatype, dataset, dataset + '.csv')
);
// Pipe the file to the response. Set {end: false} so that res isn't closed
// when the file stream ends, allowing us to continue writing to it.
datastream.pipe(res, {end: false});
// When the file is done streaming, finish the Javascript string
datastream.on('end', function() {
res.end("';");
});
}
MyView.ejs
<script language="javascript" src="/mydata/getdata?datatype=<%=datatype%>&etc.."></script>
MyViewController.js
res.view('analytics', {datatype: 'someDataType', etc...});
A slight variation on this strategy would be to use a JSONP-style approach; rather than wrapping the data in a variable in the data controller action, you would wrap it in a function. You could then call the endpoint via AJAX to get the data. Either way you'd have the benefit of a quick page load since the large data set is loaded separately, but with the JSONP variation you'd also be able to easily show a loading indicator while waiting for the data.

Categories