MEAN stack how to send a user a file - javascript

I have some code on the express controller that looks like this:
// Correct file path and write data
var currentDate = new Date();
var storagePath = path.join(__dirname,'../../public/reports/', 'Risk-Log.csv');
var source = es.readArray(riskLogs);
source.pipe(jsonCSV.csv(options)).pipe(fs.createWriteStream(storagePath));
console.log('Completed csv export to ' + storagePath);
// Send file back
res.sendFile(storagePath);
In my angular view (log.client.view.html) I have the following:
Download CSV
When I click that button... The file gets generated properly, but the file never gets sent back to the user (that they can tell).
If I look at the console debugger I get the following:
Resource {$promise: Object, $resolved: false, $get: function, $save: function, $query: function…}
I haven't done any routing with Angular or anything special since it's hitting the Node (express) controller and generating the file. I'm wondering if this is something that I should be doing in Angular?
What I'm trying to achieve is that when the user clicks that button the CSV downloads.
Any help would be MUCH appreciated.

Since using express res.send() is a buffer.... you have to send in the content type like so:
res.set('Content-Type', 'text/csv');
res.set('Content-Disposition', 'attachment');
res.send(csv); // csv object created with json-csv npm module
Big thanks to all those who commented on this!

Related

Passing data between two plain js files in ejs templating

my file structure is as follows:
file structure
I have two ejs views. I am taking a variable from index.ejs using document.querySelector. This variable is stored in index.js file.
I need to access this variable in board.js
How can I do so?
I have tried using:
module.exorts = varName and then require in board.js but it isn't working
index.js file
const btn = document.querySelector(".level1");
var levelMode;
btn.addEventListener("click", () => {
levelMode = btn.innerHTML;
alert(levelMode);
});
module.exports = levelMode;
board.js file
var levelMode = require("./index")
The console shows the following error:
uncaught reference: require is not defined
Im a new developer so take my advice with a grain of salt, but I feel I need to start by saying that js files dont "store" information that isn't the source code. Any information that you feel you need to pull from a variable is stored by the browser running the js file. If you need to pull data from the client my best advice is to first pass it to the server. You should get more familiar with the module you are using for HTTP Requests.

Send message from WeChat mini-program to web-view

I'm building WeChat Mini-Program that on one of it's pages has web-view control. For example:
page.wxml
<web-view src="https://..." bindmessage="onWebViewMessage"></web-view>
page.js
const app = getApp();
Page({
onWebViewMessage:function(e) {
console.log(e);
},
onLoad:function() {
}
});
In web-view an HTML page is loaded (index.html), that includes jweixin-1.3.2.js lib from WeChat, for connecting with WeChat API as well as connect to parent Mini-program. Page is empty, no DOM elements, just javascript that will execute when document is loaded.
It has it's javascript something like this:
index.js
document.addEventListener('DOMContentLoaded',function(){
wx.miniProgram.postMessage({data:'test'});
});
I am able to post messages from this document to mini-program without issues. Also can send some mini-program navigation commands such as wx.miniProgram.navigateTo({url:'path/to/page'}); so all seems fine. I can also get callback in Mini-program when web-view has completed loading.
Question:
How can I post message from Mini-program to web-view? For example, to pass a string or an Object to the web-view.
I have been googling for hours and can't seem to find anyone doing it, but I can't believe it's just one-way communication possible.
Any help or idea is appreciated!
I have found an effective way to pass data from mini-program to web-view content, and it seems at this moment in time, this is the only possible way to do it.
Mini-program
1. Base64 module
You will need to be able to convert normal String into Base64 string. Mini-program API has a method for converting byte array into base64 string, but that won't be usable for this purpose. So, create your own module that does that:
File: lib/b64.js
var string2base64 = function(str) {
.... here put your js code for making b64 string ....
return result;
};
module.exports = {
string2base64
};
2. Page with Web-View
In the page that has web-view control, prepare DOM element in wxml file like this:
File: pages/xxx/index.wxml
<web-view src="{{webURL}}" bindload="onWebLoad" binderror="onWebError"></web-view>
Notice that src parameter is now bound to page's webURL property. Whenever page sets value to this property, will automatically be applied to the DOM elemenet.
In file pages/xxx/index.js you will need to add base64 module:
const b64 = require('../../lib/b64.js')
note that require path may vary depending how you have setup your project
and in page's data object, add webURL and webBaseURL properties, like this:
Page({
data: {
webURL:'',
webBaseURL:'https://your/web/app/url',
messageQueue:[],
messageQueueSize:0,
.... other page properties go here ....
},
..... rest of your page code goes here .....
})
Notice that webURL is set to be empty. This means that when page loads, an empty string will be set to DOM object by default.
webBaseURL will explain just in a bit.
messageQueue is an Array that will store pending messages to be sent to web-view.
messageQueueSize is just Array length. Used for better performance, to avoid reading Array.length.
3. Start Message Queue
In onShow callback of the page, set webURL and start interval that will read messageQueue Array every 250ms. You can change the way this is done if you dislike using intervals, this was just simplest way to do theory test.
onShow: function(){
// This will start loading of the content in web-view
this.setData({webURL: this.data.webBaseURL } );
// Sends message from message queue to web-view
let _this = this;
setInterval(function(e) {
if( _this.data.messageQueueSize < 1 ) return;
_this.data.messageQueueSize --;
let msg = _this.data.messageQueue.splice(0,1);
_this.setData({webURL: _this.data.webBaseURL+"#"+msg});
},250);
}
You can see that message is appended to web-view source (url) as a hash.
webBaseURL is used to generate final URL with hash, that is then send to web-view.
4. Add a Message to the Queue
To create a message in message queue, just define following method in your page:
addMessageToQueue: function(obj) {
obj.unique = Math.round(Math.random()*100000);
let msg = b64.string2base64(JSON.stringify(obj));
this.data.messageQueue.push(msg);
this.data.messageQueueSize++;
}
Whenever you call this method, just pass an Object with whatever properties you need it to have, and it will be converted into JSON string, then to base64 string, and finally appended to the message queue.
unique property is added to make generated base64 result always different even if the rest of object properties are the same - I just needed this for the purpose of my project. You can ignore it / remove it if you do not need it.
Since there's interval running and checking on the message queue, all messages added like this will be sent to web-view in the same order they were added to the queue.
Now there's only one thing left - to add hash change listening in the HTML page we have loaded into the web-view:
HTML Web-app
1. Listen to hash change
window.addEventListener("hashchange",function(e){
let messageBase64 = window.location.hash.substr(1);
let json = window.atob( messageBase64 );
let data = JSON.parse(json);
console.log("Received data from mini-program:",data);
});
Tested on Xiaomi Mi8 Pro. I am yet to test on other devices sold in China.
Cheers!

How to create a Shared Query Folder using the vso-node-api (VSTS)?

In the VSTS Rest API, there's a piece of documentation showing me how to create a folder. Specifically, I would like to create a folder within the Shared Queries folder. It seems like I can do this with the REST API.
I would like to do the same thing with the VSTS Node API (vso-node-api). The closest analogous function I can seem to find would be WorkItemTrackingApi.createQuery. Is this the correct function to use?
When I try to use this function, I'm getting an error:
Failed request: (405)
That seems strange, since a "Method Not Allowed" error doesn't seem like the right error here. In other words, I'm not the person deciding what method (GET/POST/...etc) to use, I'm just calling the VSTS Node API's function which should be using the correct HTTP Request Method.
I think the error code would/should be different if something about my request is wrong (like providing bad parameters/data).
But, I would not be surprised if VSTS didn't like the data I provided with the request. I wrote the following test function:
async function createQueryFolder (QueryHeirarchyItem, projectId, query) {
let result = await (WorkItemTrackingApi.createQuery(QueryHeirarchyItem, projectId, query))
return result
}
I set some variables and called the function:
let projectID = properties.project // A previously set project ID that works in other API calls
let QueryHeirarchyItem = {
isFolder: true,
name: 'Test Shared Query Folder 1'
}
try {
let result = await createQueryFolder(QueryHeirarchyFunction, projectID, '')
Notice that I provided a blank string for the query - I have no idea what to provide there when all I want to create is a folder.
So, I think a lot of things could be wrong with my approach here, but also if my request parameters are wrong maybe I should be getting a 400 error? 405 leads me to believe that the VSTS Node API is making a REST call that the underlying VSTS REST API doesn't understand.
For the third parameter of the createQueryFolder, you should specify the folder path where you want to create the new folder.
Such as if you want to create a folder Test Shared Query Folder 1 under Shared Queries, you should specify parameters for createQueryFolder as:
let result = await createQueryFolder(QueryHeirarchyFunction, projectID, 'Shared Queries')

Send String to Node.js

I'm trying create a simple UI here on my iOS app to test a thing or two out but I'm having some issues here. My app is set up with a UITextField and UIButton. I'm trying to replace a string on my .js file which is saved on my virtual server. In my .js file I have below:
// Prepare a new notification
var notification = new apn.Notification();
// Display the following message (the actual notification text, supports emoji)
notification.alert = 'Hi James';
I basically would like to replace "Hi James" with whatever I typed in the UITextField in my Swift 3 project but not too sure where to start. This would be my first time sending data to .js file so anything would help. I'm thinking so far that it'd be something along the lines to below. Node.js would be similar to Javascript since it's cross platform.
func sendSomething(stringToSend : String) {
appController?.evaluateInJavaScriptContext({ (context) -> Void in
//Get a reference to the "myJSFunction" method that you've implemented in JavaScript
let myJSFunction = evaluation.objectForKeyedSubscript("myJSFunction")
//Call your JavaScript method with an array of arguments
myJSFunction.callWithArguments([stringToSend]) }, completion: { (evaluated) -> Void in
print("we have completed: \(evaluated)")
})
}
Found that on a relevant StackOverflow post so I feel like I'm getting close. Any assistant would be appreciated in advanced. Have a good one!
I recommend using the Node HTTP or ExpressJS server reading the POST fields and posting a document from your iOS app with the desired field
See
https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/

Cloud code not working

i am new at parse..trying code..trying to run a trigger required in my project.but not able to track not even i am getting any error.
i am using cloud code i.e triggers...
what i want to do is, after update or save i want to run a trigger which will a column in a class with value of 200.
Parse.initialize('APPLICATION_ID', 'JAVASCRIPT_KEY');
Parse.Cloud.afterSave("match_status", function(request)
{
var query = new Parse.Query('Wallet');
query.set("wallet_coines_number", 200);
query.equalTo("objectId", "FrbLo6v5ux");
query.save();
});
i am using afterSave trigger in which match_status is my trigger name. after that i making a object called query of Wallet class. This object will set column 'wallet_coines_number' with the value 200 where objectId is FrbLo6v5ux. after that i used save function which will execute query.
Please guide me if i am wrong, or following wrong approach.
Thank You !
Have you read the Parse documentation on Cloud Code ?
The first line of your code is only relevant when you are initialising Parse JavaScript SDK in a web page, you do not need to initialise anything in Parse cloud code in the main.js file. Also you cannot use a query to save/update an object. A query is for searching/finding objects, when you want to save or update an object you need to create a Parse.Object and save that.
So you code should become something like:
Parse.Cloud.afterSave("match_status", function(request) {
var wallet = new Parse.Object('Wallet');
wallet.set("wallet_coines_number", 200);
wallet.set("objectId", "FrbLo6v5ux");
wallet.save();
});

Categories

Resources