I have a problem. I'm sending file via AJAX (XMLHttpRequest). Anyways. PHP function is returning a response array encoded to JSON. I can catch array in JavaScript but i can't access to specified key in array.
Here is the console log of this array:
{"data":"cos","data1":"cos1"}
I have my JavaScript file:
$('input[name=zdjecie]').on("change",function() {
var inputfile = document.querySelector('#file');
var file = inputfile.files[0];
$('button[type=submit]').addClass('disabled');
var formData = new FormData();
var request = new XMLHttpRequest();
request.upload.addEventListener('progress', function(e){
var pro = Math.round(e.loaded/e.total * 100);
if(pro == 100) {
$('#upload_progress').css({'width':pro+'%', background:'#00A65A'});
$('button[type=submit]').removeClass('disabled');
}
else {
$('#upload_progress').css({'width':pro+'%', background:'#3C8DBC'});
}
}, false);
formData.append('file', file);
request.open('post', '/admin/ajax/upload-admin-photo');
request.send(formData);
request.onloadend = function() {
var result = request.response;
console.log(result.data);
};
});
Now PHP function that is executing after POST request:
/**
* #Route("/admin/ajax/upload-admin-photo")
*/
public function ajaxUploadAdminPhotoAction(Request $request)
{
$data = $_FILES;
$response = array("data" => 'cos', 'data1' => 'cos1');
return new Response(json_encode($response));
}
Console log of variable result: {"data":"cos","data1":"cos1"}
Console log of variable result.data: undefined
I really need some help. I was trying everything! :(
You need to parse (=decode) the string '{"data":"cos","data1":"cos1"}' to a json first:
var result = JSON.parse(request.response);
// now you can access it's params:
console.log(result.data);
see the manual for more information.
Related
I'm trying to get a script to work, which is called sfo.js.
The repo mentions only this usage:
keys = parse_sfo(Some_ArrayBuffer);
console.log(keys['TITLE']);
Looking into the sfo.js, parse_sfo has the sfoBytes argument.
From this I've concluded the sfoBytes argument needs to be an arraybuffer of file bytes.
I've tried to make a script that parses the SFO file into a array of bytes:
<script src="sfo.js"></script>
<script>
function stringToArrayBuffer(str) {
var buf = [];
for (var i=0, strLen=str.length; i<strLen; i++) {
buf[i] = str.charCodeAt(i);
}
console.log(buf);
return buf;
}
function testing(url) {
var request = new XMLHttpRequest();
request.open('GET', url, false);
request.send(null);
if (request.status === 200) {
console.log(request.response);
var response = request.response;
var array = stringToArrayBuffer(response);
return array;
} else {
alert('Error!');
}
}
var data = testing('param.sfo');
var sfo = parse_sfo(data);
</script>
That throws an error in the console:
Uncaught RangeError: byte length of Uint32Array should be a multiple of 4 at new Uint32Array (<anonymous>)
at readUint32At (sfo.js:20)
at parse_sfo (sfo.js:113)
at (index):29
I'm pretty sure I'm doing something wrong. Does anybody understand how I can make the script work properly?
I have a sample file for param.sfo: https://filebin.net/gghosrp6u93jn7y8 (if linking to a download is not allowed please let me know)
Ok, finally the working example.
I've found a small param.sfo file in the internet.
Notes:
there are 2 versions of file reader: local and remote
in the snippet below you can test both (I've added my param.sfo as an external link to test 'remote'). To test 'local' you just need to select any sfo file from you PC.
as a result I show all the keys, not only 'TITLE' (as it is in your question). You can then select desired key
function getSfoLocal(callback) {
// for now I use local file for testing
document.querySelector('input').addEventListener('change', function() {
var reader = new FileReader();
reader.onload = function() {
var arrayBuffer = this.result;
var array = new Uint8Array(arrayBuffer);
// var binaryString = String.fromCharCode.apply(null, array);
if (typeof callback === 'function') callback(array);
}
reader.readAsArrayBuffer(this.files[0]);
}, false);
}
function getSfoRemote(url, callback) {
var concatArrayBuffers = function(buffer1, buffer2) {
if (!buffer1) {
return buffer2;
} else if (!buffer2) {
return buffer1;
}
var tmp = new Uint8Array(buffer1.length + buffer2.length);
tmp.set(buffer1, 0);
tmp.set(buffer2, buffer1.byteLength);
return tmp.buffer;
};
fetch(url).then(res => {
const reader = res.body.getReader();
let charsReceived = 0;
let result = new Uint8Array;
reader.read().then(function processText({
done,
value
}) {
// Result objects contain two properties:
// done - true if the stream has already given you all its data.
// value - some data. Always undefined when done is true.
if (done) {
if (typeof callback === 'function') callback(result);
return result;
}
// value for fetch streams is a Uint8Array
charsReceived += value.length;
const chunk = value;
result = concatArrayBuffers(result, chunk);
// Read some more, and call this function again
return reader.read().then(processText);
});
});
}
function getSfo(type, url, callback) {
if (type === 'local') getSfoLocal(callback);
if (type === 'remote') getSfoRemote(url, callback);
}
getSfo('local', null, (data) => {
keys = parse_sfo(data);
console.log('LOCAL =', keys);
});
function goremote() {
getSfo('remote', 'https://srv-file9.gofile.io/download/Y0gVfw/PARAM.SFO', (data) => {
keys = parse_sfo(data);
console.log('REMOTE =', keys);
});
}
div { padding: 4px; }
<!--script src="https://rawcdn.githack.com/KuromeSan/sfo.js/c7aa8209785cc5a39c4231e683f6a2d1b1e91153/sfo.js" for="release"></script-->
<script src="https://raw.githack.com/KuromeSan/sfo.js/master/sfo.js" for="develop"></script>
<div>Local version: <input type="file" /></div>
<div>Remote version: <button onclick="goremote()">Go remote</button></div>
P.S. It seems that gofile.io service that I've used for remote example is not visible sometimes. If you have permanent link to param.sfo just let me know. But now I have to visit my file, and only after that it becomes visible.
You are using some 20 years old JavaScript.
Please use fetch add TextEncoder for your own sanity.
fetch(url).then(res => res.json().then(data => {
const encoder = new TextEncoder()
const bytes = encoder.encode(data)
parse_sfo(data)
})
sfoBytes should be the actual array buffer of the sfo file. It's simpler than what you are trying, you shouldn't need to convert the request response with stringToArrayBuffer since you can get an array buffer from XMLHttpRequest. Also, the SFO file isn't a text file, it's binary, so conversion from string wouldn't work anyway.
Changing your request to get a arraybuffer response type should do it like this:
function testing(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.send(null);
if (request.status === 200) {
console.log(request.response);
var response = request.response;
var sfo = parse_sfo(response);
} else {
alert('Error!');
}
}
I have two values I want to send but I couldn't figure it out.
Im currently sending 1 value like that:
JS:
req.open('POST', '../Ajax/doc.php?id=' + id, true);
req.send();
PHP:
$id = $_REQUEST["id"];
And now I have another value id2 which I want to send in the same way..
Thanks
Since you are using post, the SEND function accepts the query string as a parameter. Then just replace my var2 with what it is you are trying to send and use POST in PHP to make it easier for you to know the array to use for POST submissions.
const data = {
id: 123,
var2: 987,
foo: 'bar',
}
req.open('POST', '../Ajax/doc.php', true)
req.send(
Object.keys(data)
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
.join('&')
)
PHP
$id = $_POST["id"];
$var2 = $_POST["var2"];
You can send multiple value using FormData.
function send() {
var uri = "your_url";
var xhr = new XMLHttpRequest();
var fd = new FormData();
xhr.open("POST", uri, true);
fd.append('title', 'Hello World');
fd.append('content', 'Just Hello World');
// Initiate a multipart/form-data upload
xhr.send(fd);
}
window.onload = function () {
btn_send = document.querySelector('#btn-click');
btn_send.addEventListener('click', function () {
send();
})
}
So, I have a JS script that sends a request to the server and that works fine. However, I want the frontend to recieve a response containing some information and read it on the frontend and execute a function.
uploadButton.addEventListener("click", () => {
var formData = new FormData();
var request = new XMLHttpRequest();
request.open("POST", "/Page/Upload");
request.send(formData);
if (request.response.result == "Success") {
console.log("Result is success")
window.location = request.response.url;
}
}
My controller looks like this.
[HttpPost("/page/upload")]
public IActionResult Upload()
{
*working parts pertaining to reading the request are omitted*
var redirectUrl = Request.Host + "/" + page.PageURL;
return Json(new { result = "Success", url = redirectUrl});
}
What I want is for my JS script to access the returned Json and its contents. How would I do this?
Try using the following code. It will subscribe the readystatechange event and run when API response has been received
uploadButton.addEventListener("click", () => {
var formData = new FormData();
var request = new XMLHttpRequest();
request.open("POST", "/Page/Upload");
request.send(formData);
request.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
var responseData = JSON.parse(this.responseText);
if (responseData.result == "Success") {
console.log("Result is success")
window.location = responseData.url;
}
}
});
});
I created a generator for PDF files that creates the file and sends to a specific path automatically after creation. Still I want to download it right after but didn't know how to do that. Any help would be appreciated. This is my generatorPdf.js :
module.exports={
pdfGenerator:function(data,pathfile){
var fonts = {
Roboto: {
normal: 'server/pdfgenerator/fonts/Roboto-Regular.ttf',
bold: 'server/pdfgenerator/fonts/Roboto-Medium.ttf',
italics: 'server/pdfgenerator/fonts/Roboto-Italic.ttf',
bolditalics: 'server/pdfgenerator/fonts/Roboto-MediumItalic.ttf'
}
};
var datePaiements='';
var dateFinPaiements='';
if(data.abonnement[0].datePaiement!=null)
datePaiements= new Date( data.abonnement[0].datePaiement.toString());
if(datePaiements!=='')
{
dateFinPaiements= ('0'+datePaiements.getDate()).slice(-2).toString()+'/'+('0'+(datePaiements.getMonth()+1)).slice(-2).toString()+'/'+(datePaiements.getFullYear()+1).toString();
datePaiements=('0'+datePaiements.getDate()).slice(-2).toString()+'/'+('0'+(datePaiements.getMonth()+1)).slice(-2).toString()+'/'+datePaiements.getFullYear().toString();
}
var dateFacture= new Date(data.abonnement[0].timestampCreation.toString());
dateFacture= ('0'+dateFacture.getDate()).slice(-2).toString()+'/'+('0'+(dateFacture.getMonth()+1)).slice(-2).toString()+'/'+dateFacture.getFullYear().toString();
var PdfPrinter = require('pdfmake/src/printer');
var printer = new PdfPrinter(fonts);
var fs = require('fs');
var dd = {
content: [ ..............],
footer:{.............}
}
try{
var pdfDoc = printer.createPdfKitDocument(dd);
if (fs.existsSync(pathfile)) {//server/pdfgenerator/documentpdf/basics21.pdf
fs.unlink(pathfile, (err) => {//server/pdfgenerator/documentpdf/basics21.pdf
if (err) {
console.error(err)
return
}
})
}
pdfDoc.pipe(fs.createWriteStream(pathfile)).on('finish',function(){//server/pdfgenerator/documentpdf/basics21.pdf
});
}
catch(e){
console.log(e);
return null;
}
}
}
and this is my remote method in Loopback to send the pdf to a path and where probably I have to do the download of the file:
cm_abonnements.getAbonnementById= async (options,req,res)=>{
const token = options && options.accessToken;
const userId = token && token.userId;
try{
if(userId!==null){
let dataComedien= await app.models.cm_comediens.getComedienByUser(userId);
let argAbn={};
const form = new formidable.IncomingForm();
var formPromise = await new Promise(function(resolve,reject){
form.parse(req,function(err,fields,files){
if(err)
{
reject(err);
return-1
}
console.log(fields.key)
argAbn.idAbonnement=fields.key;
resolve();
})
})
let dataFac=await cm_abonnements.find({where :{and :[{idAbonnement:argAbn.idAbonnement},{idComedien : dataComedien.idComedien}]}});
var data={abonnement:[]};
data.abonnement=dataFac;
var str_date= new Date(dataFac[0].timestampCreation.toString());
var nameFile= 'Fac_'+dataFac[0].idFacture+'_'+str_date.getFullYear().toString()+'-'+('0'+str_date.getMonth()+1).slice(-2).toString()+'-'+('0'+str_date.getDate()).slice(-2).toString()+'.pdf';
var path='public/upload/Comediens/'+dataComedien.idComedien.toString()+'/factures/'+nameFile;
createPdf.pdfGenerator(data,path);
return dataFac;
}
return null;
}
catch(e){
console.log(e);
return null;
}
}
cm_abonnements.remoteMethod(
'getAbonnementById',{
http:{
verb:'POST'
},
description:'Get detail facture by number facture',
accepts:[
{arg:"options", "type":"object","http":"optionsFromRequest"},
{ arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}}
],
returns:{arg:'data',root:true}
}
);
Any help would be appreciated. Thank you
You need to send the following HTTP headers:
Content-Type: application/pdf
Content-Disposition: inline; filename="download.pdf"
After data is generated and pdf file is stored, there are 2 steps left to implement the "download" feature:
Return HTTP response to browser, with Content-Type header as application/pdf, and Content-Disposition header as attachment; filename="yourname.pdf". Normally, this would be handled automatically by web framework. I'm not familiar with loopback, so take Express for example:
In generatorPdf.js, add a callback to listen the finish event:
pdfGenerator:function(data, pathfile, callback){
...
pdfDoc.pipe(fs.createWriteStream(pathfile)).on('finish', callback);
...
}
When pdfGenerator function is used, pass a callback function parameter. If the pdf work is "finished", return response to browser using res.download() (It's Express API, but I believe loopback has similar API as loopback is built on top of Express):
var nameFile=...
var path=...
createPdf.pdfGenerator(data, path, function() {
res.download(path, nameFile);
});
In browser side, if it's an AJAX request (I guess so, as you mentioned it is a POST request), you need to handle the request with some blob operation. Here is an example snippet, with explanation comment:
var req = new XMLHttpRequest();
req.open('POST', '/download', true); // Open an async AJAX request.
req.setRequestHeader('Content-Type', 'application/json'); // Send JSON data
req.responseType = 'blob'; // Define the expected data as blob
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status === 200) { // When data is received successfully
var data = req.response;
var defaultFilename = 'default.pdf';
// Or, you can get filename sent from backend through req.getResponseHeader('Content-Disposition')
if (typeof window.navigator.msSaveBlob === 'function') {
// If it is IE that support download blob directly.
window.navigator.msSaveBlob(data, defaultFilename);
} else {
var blob = data;
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = defaultFilename;
document.body.appendChild(link);
link.click(); // create an <a> element and simulate the click operation.
}
}
}
};
req.send(JSON.stringify({test: 'test'}));
I am trying to :
Send a zip file via xmlhttp to the client
then read the file using zip.js and render its contents
I successfully receive the binary of the file i.e. the success callback is called but I get and error when I try to do getEntries. I think the error is with the way of sending stream , please help.
Error msg :
Error in reading zip file
My client side code (using angular) :
$http.get(window.location.origin + '/book/'+bookName,{responseType:"Blob"}).
success(function (data , error) {
var a = new Uint8Array(data);
//var dataView = new DataView(data);
//var blob = new Blob(dataView.buffer);
zip.useWebWorkers = true;
zip.workerScriptsPath = '/js/app/';
zip.createReader(new zip.BlobReader(data), function(reader) {
// get all entries from the zip
reader.getEntries(function(entries) { //HERE I GET THE ERROR
if (entries.length) {
// get first entry content as text
entries[0].getData(new zip.TextWriter(), function(text) {
// text contains the entry data as a String
console.log(text);
// close the zip reader
reader.close(function() {
// onclose callback
var a = 0;
});
}, function(current, total) {
// onprogress callback
var a = 0;
});
}
});
},
function(error) {
// onerror callback
var a = 0;
});
})
.error( function (data , error) {
var a = 0;
});
My Server side code on Node:
router.get('/book/:bookName',function (req , res ) {
console.log('Inside book reading block : ' + req.params.bookName);
req.params.bookName += '.zip';
var filePath = path.join(__dirname,'/../\\public\\books\\' ,req.params.bookName );
var stat = fileSystem.statSync(filePath);
res.writeHead(200, {
//'Content-Type': 'application/zip',
'Content-Type': 'blob',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream(filePath);
// replace all the event handlers with a simple call to readStream.pipe()
readStream.pipe(res);
});
It is probable that you might have already found a solution. I faced the same problem today and this is how I solved it in plain javascript:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'assets/object/sample.zip', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
// response is unsigned 8 bit integer
var responseArray = new Uint8Array(this.response);
var blobData = new Blob([responseArray], {
type: 'application/zip'
});
zip.createReader(new zip.BlobReader(blobData), function(zipReader) {
zipReader.getEntries(displayEntries);
}, onerror);
};
xhr.send();
The problem I see in your code is that you are changing the value to Uint8Array and assigning it to var a, but still use the raw data in blobreader. Also the blob reader required blob and not an array. So you should have converted var a into blob and then used it for reading.