I have a API that returns image and want to display the image on the browser. I am using iron:router package. On the client side user click on a link which is a basically a server side iron:route. The route makes call to API and should display the response of API on the browser.
client js : -
Template.images.events({
'click .image': function (event, template) {
event.preventDefault();
var docId = $(event.target).attr('data-docId');
var imageType = "raw";
var param = {"docId":docId,"imageType":imageType};
params = 'width=' + window.innerWidth;
params += ', height=' + window.innerHeight;
params += ', top=0, left=0'
params += ', fullscreen=yes';
var win = window.open("/Image/?param=" + encodeURIComponent(Base64.encode(JSON.stringify(param))), "_blank", params);
}
});
Iron:route : -
Router.route('/checkImage', function () {
var decoded = Base64.decode(decodeURIComponent(this.params.query.param));
var param = JSON.parse(decoded);
var docId = param.docId;
var content="";
Meteor.call('imageApi', docId, imageType, function (error, result) {
if (error) {
content = "";
} else
content = new Buffer(result);
});
if (content == "") {
this.response.writeHeader('200', {
'Content-Type': 'image/jpeg',
'Content-Disposition': "inline",
'Access-Control-Allow-Origin': '*'
});
this.response.write('<html><body><p>No content for image found.</p></body></html>');
this.response.end();
}
else {
this.response.writeHeader('200', {
'Content-Type': 'image/jpeg'
'Content-Disposition': 'inline; filename=image.jpg'
});
this.response.write(content);
this.response.end();
}
}, {where: 'server'});
Server method : -
imageApi: function (docId, imageType) {
var url = "API url with the paramters ";
var response;
try{
response = HTTP.call('GET', url, {
headers: {"Content-Type": "image/jpeg"},
responseType: "buffer"
});
}catch (error) {
logger.error("imageApi - Exception in image API " + error);
return false;
}
if (response.statusCode == 200) {
return new Uint8Array(response.content);
}
else {
logger.error"imageApi - Response issue: " + response.statusCode);
return "";
}
return "";
}
I am not able to display the image data on the browser. Do you think something is wrong in this approach or else if there is another way to render image.
Related
Am using AEM Site search component from core components. query builder URL is not returning a different json.
Once after searching with a text, am getting a json. Thereafter doing any search with new search text, am getting only the same json, not a new json. Only old response am getting in all search.
var request = new XMLHttpRequest();
if (self._hasMoreResults) {
var response;
var url = self._action + "?" + serialize(self._elements.form) + "&" + PARAM_RESULTS_OFFSET + "=" + self._resultsOffset;
request.open("GET", url, true);
request.onload = function() {
setTimeout(function() {
toggleShow(self._elements.loadingIndicator, false);
toggleShow(self._elements.icon, true);
}, LOADING_DISPLAY_DELAY);
if (request.status == 200 ) {
debugger;
var data = JSON.parse(request.responseText);
if (data.length > 0) {
self._generateItems(data, self._elements.results);
self._markResults();
toggleShow(self._elements.results, true);
} else {
self._hasMoreResults = false;
}
if (self._elements.results.querySelectorAll(selectors.item.self).length % self._properties.resultsSize > 0) {
self._hasMoreResults = false;
}
} else {
// error status
}
};
toggleShow(self._elements.loadingIndicator, true);
toggleShow(self._elements.icon, false);
request.send('');
}
};
I've got a server side route I'm using to download a file. This is called from a client side button click and everything is working fine. However, once the button has been clicked once it will not work again until another route is loaded and you go back. How can I code it so that the button can be clicked multiple times and the server side route be fired each time?
My button code looks like this...
'click #view_document_download': function (event, tmpl) {
Router.go('/download_document/' + this._id);
}
And my server side route looks like this...
Router.route('/download_document/:_id', function () {
//Get the file record to download
var file = files.findOne({_id: this.params._id});
//Function to take a cfs file and return a base64 string
var getBase64Data = function(file2, callback) {
var readStream = file2.createReadStream();
var buffer = [];
readStream.on('data', function(chunk) {
buffer.push(chunk);
});
readStream.on('error', function(err) {
callback(err, null);
});
readStream.on('end', function() {
callback(null, buffer.concat()[0].toString('base64'));
});
};
//Wrap it to make it sync
var getBase64DataSync = Meteor.wrapAsync(getBase64Data);
//Get the base64 string
var base64str = getBase64DataSync(file);
//Get the buffer from the string
var buffer = new Buffer(base64str, 'base64');
//Create the headers
var headers = {
'Content-type': file.original.type,
'Content-Disposition': 'attachment; filename=' + file.original.name
};
this.response.writeHead(200, headers);
this.response.end(buffer, 'binary');
}, { where: 'server' });
use a element instead of js 'click' event
page html
page js in server
Router.route("/download_document/:fileId", function(){
var file = files.findOne({_id: this.params.fileId});
var contentFile = //file text
let headers = {
'Content-Type': 'text/plain',
'Content-Disposition': "attachment; filename=file.txt"
};
this.response.writeHead(200, headers);
this.response.end(contentFile);
},
{where: "server", name: "download"}
);
Maybe you should just return an Object from your Server via a method and form it to a file on the client side? if possible..
To create a file on the client side is really simple, and you don't have to deal with Routers at this point.
function outputFile(filename, data) {
var blob = new Blob([data], {type: 'text/plain'}); // !note file type..
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
}
else{
var elem = window.document.createElement('a');
elem.href = window.URL.createObjectURL(blob);
elem.download = filename;
document.body.appendChild(elem)
elem.click();
document.body.removeChild(elem);
}
}
function getContentAndOutputFile() {
var content = document.getElementById('content').value;
outputFile('file.txt', content);
}
<input id="content" value="test content"/>
<button onClick="getContentAndOutputFile()">Create File</button>
How can i get POST raw body in Meteor restivus?
tried something, but it's not working.
this is the code.
if(Meteor.isServer) {
var Api = new Restivus({
useDefaultAuth: true
});
Api.addRoute('test', {authRequired: false}, {
post: {
action: function() {
var response;
var readable = this.request;
var rawBody = "";
readable.on('data', function(chunk) {
rawBody += chunk;
});
readable.on('end', Meteor.bindEnvironment(function() {
//dosometing and insert into Collection
//make response data
}));
return response;
}
}
});
}
it's proceed return response and then readable.on('end'.. )
so, it's error by return null.
if i moved return response into readable.on('end'...), also same error.
i think if can wait POST return until readable.on('end'..) is finished, it will be work, but i don't know how.
You can use node-fibers's Future to wait until readable.on('end', ..) is called.
if(Meteor.isServer) {
var Future = Npm.require('fibers/future');
var Api = new Restivus({
useDefaultAuth: true
});
Api.addRoute('test', {authRequired: false}, {
post: {
action: function() {
var response;
var readable = this.request;
var rawBody = "";
var future = new Future();
readable.on('data', function(chunk) {
rawBody += chunk;
});
readable.on('end', Meteor.bindEnvironment(function() {
//dosometing and insert into Collection
//make response data
future.return(response); //response is what you want to return
// you can also throw error using future.throw(err);
}));
return future.wait();
}
}
});
}
I need to upload 'on fly' user's image. But i get error 503 Service Unavailable.
user.js
Meteor.subscribe('userImages');
Template.userProfil.events({
'change [name=userPhotoUpload]': function(event) {
event.preventDefault();
FS.Utility.eachFile(event, function(file) {
var newFile = new FS.File(file);
newFile.metadata = {
createdBy:Meteor.userId(),
}
userImages.insert(newFile, function (err, fileObj) {
if (err){
// handle error
} else {
// handle success depending what you need to do
var currentUserId = Meteor.userId();
var imagesURL = {
"profile.userImg": '/cfs/files/userImages/' + fileObj._id + '/' + fileObj.name()
};
Meteor.users.update(currentUserId, {$set: imagesURL});//there I get url and
}
});
});
}
});
router.js
Router.route('/organizer', {
name: 'userProfil',
template: 'userProfil',
data: function() {
var currentUser = Meteor.userId();
return Meteor.user({_id: currentUser});
}
});
user-img.html
<img src="{{profile.userImg}}">
after uploding image i get this err:
http://localhost:3000/cfs/files/userImages/wNjvF8uuN8j6fd8md/exampl2.jpg 503 (Service Unavailable)
But this path is absolutely correct, and after manual reloading page it's work.
How can I solve this problem?
Ok, I found some solution, but I don't think that it's correct way. Maybe someone have better decision?
Changing:
user.js
'change [name=userPhotoUpload]': function(event) {
event.preventDefault();
FS.Utility.eachFile(event, function(file) {
var newFile = new FS.File(file);
newFile.metadata = {
createdBy:Meteor.userId(),
}
userImages.insert(newFile, function (err, fileObj) {
if (err){
// handle error
} else {
var currentUserId = Meteor.userId();
var intervalHandle = Meteor.setInterval(function () {
console.log("Inside interval");
// changes here:
if (fileObj.hasStored("userImages")) {
//checked if image was stored
var imagesURL = {
"profile.userImg": '/cfs/files/userImages/' + fileObj._id + '/' + fileObj.name()
};
Meteor.users.update(currentUserId, {$set: imagesURL});
// if file has stored, stop interval
Meteor.clearInterval(intervalHandle);
}
}, 1000);
}
});
});
}
I have the below data coming in form of array from a url.
[{"title":"hey hi","body":"hello","url":"https://simple-push-demo.appspot.com/","tag":"new"}]
service-worker.js
it has the above url in fetch()
'use strict';
console.log('Started', self);
self.addEventListener('install', function(event) {
self.skipWaiting();
console.log('Installed new', event);
});
self.addEventListener('activate', function(event) {
console.log('Activatednew', event);
});
self.addEventListener('push', function(event) {
try{
console.log('Push message', event);
var ev = event;
//sample
return fetch("http://localhost/push-notifications-master/app/json.php").then(function(ev,response) {
response = JSON.parse(JSON.stringify(response));
return response;
}).then(function(ev,j) {
// Yay, `j` is a JavaScript object
console.log("j", j);
for(var i in j) {
var _title = j[i].title;
var _body = j[i].body;
var _tag = j[i].tag;
console.log("_body", _body);
}
ev.waitUntil(
self.registration.showNotification("push title", {
body: _body,
icon: 'images/icon.png',
tag: _tag
}));
});
return Promise.all(response);
}
catch(e){console.log("e", e)}
});
I am trying to see the above array data coming from that particular url in console.log("j",j);. but it shows undefined. How can i get dymanic data in sw.js Please Guide.
In your addEventListener('push' .... method, I think it might be better to wait for a response before parsing it.
Also, to be checked, but your php request should be in https (not checked by myself, but my request are on https).
Here how I do this :
event.waitUntil(
fetch('YOUR PHP URL').then(function(response) {
if (response.status !== 200) {
console.log('Problem. Status Code: ' + response.status);
throw new Error();
}
// Examine the text in the response
return response.json().then(function(data) {
if (data.error || !data.notification) {
console.error('The API returned an error.', data.error);
throw new Error();
}
var title = data.notification[0].title;
var body = data.notification[0].body;
var icon = data.notification[0].icon;
var notificationTag = data.notification[0].tag;
return self.registration.showNotification(title, {body: body,icon:icon, tag: notificationTag});
});
})
);
The json :
{"notification" : [{"title":"TITLE","body":"BODY","icon":"URL TO ICON","tag":"TAG"}]}
Hope it can be useful.