Meteor: passing variable from server to client - javascript

I want to pass a variable from server side to a template in the client side.
In main.html, I have this template:
<template name="hello">
...
<p>{{privateKey}}</p>
</template>
In main.js, I want something like:
if (Meteor.isClient) {
Template.hello.helpers({
privateKey : function () {
return 'call to function makePrivateKey';
}
});
}
if (Meteor.isServer) {
Meteor.methods({
makePrivateKey: function() {
var privKey = bitcoinjs.ECKey.makeRandom();
return privKey.toWIF();
}
});
}
How can I invoque the function makePrivateKey from server side and print
the private key in my template ?
I don't want to use session variable or dynamic variable.

Seems like a strange structure to me. You wouldn't want a helper to generate a private key, I don't think. Every time that template renders, it would generate a key and print it. But you couldn't just call the method like this anyway, as using Meteor.call on the client requires a callback, and so again, this is not the way to do this. However, this could work:
if (Meteor.isClient) {
Template.hello.events({
'click .generate-key': function () {
Meteor.call('makePrivateKey', function (error, result) {
if (!error) {
Session.set('credentials/privKey', result.privKey);
}
else {
// handle error
}
})
}
});
Template.hello.helpers({
privateKey: function () {
return Session.get('credentials/privKey');
}
});
}
if (Meteor.isServer) {
Meteor.methods({
makePrivateKey: function () {
try {
var privKey = bitcoinjs.ECKey.makeRandom();
return {privKey: privKey.toWIF()};
} catch (e) {
throw Meteor.Error('some-error', 'Bad things happened.');
}
}
});
}

In general using the Meteor 'Method' would be the way to go:
if (Meteor.isClient) {
Template.hello.helpers({
privateKey : function () {
return Meteor.call(makePrivateKey);
}
});
}

Related

Meteor restarts client after Meteor.call()

I'm using: meteor-base#1.4.0.
I want to redirect the user to a different page but after the insert the client it's refreshed. This means that i'm filling up a form, I store the data, I do the navigation and then with the client refresh I'm back to the form page.
// Methods.js
import { Meteor } from "meteor/meteor";
import { Players } from "../imports/api/players";
Meteor.methods({
insertPlayer(player) {
Players.insert(player);
}
})
I'm calling the method like this:
// New-player.jsx
Meteor.call("insertPlayer", player, (error) => {
if(error) {
alert("Oups something went wrong: " + error.reason);
} else {
this.props.history.push("/");
}
})
And i'm storing the values as:
// Players.js
Players.allow({
insert() { return false; },
update() { return false; },
remove() { return false; }
});
Players.deny({
insert() { return true; },
update() { return true; },
remove() { return true; }
})
Any idea what it might cause this behavior?
I'm I missing any config?
The project can be found here: https://github.com/roedit/soccer-app
I assume you are using a form submit event? Make sure before you call the Meteor Method insertPlayer you are using event.preventDefault(). If you do not event.preventDefault(), the page will refresh.

$log anonymous function angular js not working

I have a problem when I try to log some data inside the function of webtorrent.
I want to log some values of this.client.add but I don't have access.
Some idea of what's going on here?
import Webtorrent from 'webtorrent';
class PlaylistController {
/** #ngInject */
constructor($http, $log) {
this.log = $log;
this.client = new Webtorrent();
$http
.get('app/playlist/playlist.json')
.then(response => {
this.Torrent = response.data;
});
}
addTorrent(magnetUri) {
this.log.log(magnetUri);
this.client.add(magnetUri, function (torrent) {
// Got torrent metadata!
this.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
this.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}
}
export const playlist = {
templateUrl: "app/playlist/playlist.html",
controller: PlaylistController,
bindings: {
playlist: '<'
}
};
Another thing its I use yeoman for the scaffold of my app and its has JSLint with console.log forbidden and its said that you must use angular.$log, but the thing its I don't wanna change that, I wanna understand the problem here.
You either need to refer to this (the class) as another variable to use inside the function(torrent) function or use arrow functions so that this reference remains the class one.
Solution 1, using another variable to ref the class:
addTorrent(magnetUri) {
this.log.log(magnetUri);
var that = this;
this.client.add(magnetUri, function (torrent) {
// Got torrent metadata!
that.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
that.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}
Solution 2, using arrow functions:
addTorrent(magnetUri) {
this.log.log(magnetUri);
this.client.add(magnetUri, torrent => {
// Got torrent metadata!
this.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
this.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}

Sinon stub callFake function not replacing original function

So this is the (snipped) code for a chatbot. I want to override the sendMessage() function to just echo the message argument. In this case, the original function runs and gives an error at the 2nd line of the function. Obviously, modules aren't loaded and I don't need them to. This is a test for the eventHandler to echo the right messages. Ideas?
var modules = require('./modules');
console.log('[tose] Loading modules: ', Object.keys(modules));
function eventHandler(channel, type, data, react=()=>{}) {
switch (type) {
case 'new_message':
console.log('[tose][new_message]', channel, 'from:', data.cid, 'message:', data.message);
if (regexTemplates.testSearch.test(data.message.toLowerCase())) {
...
} else {
sendMessage(channel, data.cid, data.message); // Basic echo message
}
break;
}
}
// The function to be stubbed
function sendMessage(channel, cid, message) {
console.log('[tose][send_message]', channel, 'to:', cid, 'message:', message);
coms[channel].sendMessage(cid, message); // Getting error here thus not really stubbed
}
exports.eventHandler = eventHandler;
exports.sendMessage = sendMessage
And the test:
describe('Tose core', function() {
describe('Process messages', function() {
before(function() {
var stub = sinon.stub(tose, 'sendMessage').callsFake(function(channel, cid, message) {
assert.equal(message, 'Test message');
return message
});
});
after(function() {
tose.sendMessage.restore();
});
it('should echo messages', function() {
var data = {message: 'Test message'}
tose.eventHandler('test', 'new_message', data)
assert(tose.sendMessage.calledOnce);
});
});
});
The problem here is that when you use Sinon to stub an object's function, you're stubbing that (and only that) object's function.
Your code (the first code block) is using the local definition of the sendMessage function.
When you stub the tose object (in the second code block), you are changing the sendMessage function thats on the tose object and not the local definition of the function.
There are many different ways you could approach this, one of which is:
var modules = require('./modules');
var functions = {
eventHandler: eventHandler,
sendMessage: sendMessage,
};
console.log('[tose] Loading modules: ', Object.keys(modules));
function eventHandler(channel, type, data, react=()=>{}) {
switch (type) {
case 'new_message':
console.log('[tose][new_message]', channel, 'from:', data.cid, 'message:', data.message);
if (regexTemplates.testSearch.test(data.message.toLowerCase())) {
...
} else {
functions.sendMessage(channel, data.cid, data.message); // Basic echo message
}
break;
}
}
// The function to be stubbed
function sendMessage(channel, cid, message) {
console.log('[tose][send_message]', channel, 'to:', cid, 'message:', message);
coms[channel].sendMessage(cid, message); // Getting error here thus not really stubbed
}
module.exports = functions;
Note: functions is not a descriptive name - feel free to change it to something that is more meaningful.

Meteor js | Display Json in view via helper

Im struggling with an issue using Meteor JS.
I call an api wich return me a Json array wich look like the one returned on this url (I don't put the whole array here cause of the size): https://blockchain.info/address/12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?format=json&offset=0
I call it server side like :
if (Meteor.isServer) {
Meteor.methods({
getWalletPreviousTx: function() {
var url = "https://blockchain.info/address/12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?format=json&offset=0";
var result = Meteor.http.get(url);
if(result.statusCode==200) {
var tx = JSON.parse(result.content);
return tx;
} else {
console.log("Response issue: ", result.statusCode);
var errorJson = JSON.parse(result.content);
throwError("Couldn't fetch wallet balance from Blockchain, try again later !");
}
}
});
}
And i retrieve it to my view via an helper in a specific template :
Template.wallet.helpers({
addrTxs: function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx);
return [tx];
});
}
});
The console.log in the helper actually log my Json array wich mean it have access to it.
Now the part im struggling with is to retrieve this Json to my view, i've tried a lot of way and none of them works, actually i have this in my view :
<template name="wallet">
<table>
{{#each addrTxs}}
<ul>
{{> addrTx}}
</ul>
{{/each }}
</table>
</template>
The part of the Json I want to display is the "addr" and "value" of each transactions :
"inputs":[
{
"sequence":4294967295,
"prev_out":{
"spent":true,
"tx_index":97744124,
"type":0,
"addr":"1AWAsn8rhT555RmbMDXXqzrCscPJ5is5ja",
"value":50000,
"n":0,
"script":"76a914683d704735fd591ba9f9aebef27c6ef00cbd857188ac"
}
}
]
Fact is, i never managed to display anything from this Json array in my view, even puting directly this in my view doesn't show anything :
{{addrTxs}}
What am I doing wrong ? Can anyone help with this ?
Thanks for reading.
----------------------- Edit ---------------------
I think the problem is more that my helper and template are loaded before the api call is finished (because the console.log appear in my console like 3seconds after my page is rendered). How can i make my helper wait until the api call is finished before rendering it in the view ? I use iron router.
I have tried to add a waitOn action on my route in order to wait until my api call is finished :
Router.route('/wallet', {
name: 'wallet',
template: 'wallet',
loadingTemplate: 'loading',
waitOn: function () {
Meteor.call('getWalletPreviousTx', function(error, result) {
if(!error) {
Ready.set(result)
}
});
return [
function () { return Ready.get(); }
];
},
action: function () {
if (this.ready())
this.render();
else
this.render('loading');
}
});
The above code with the waitOn action seems to work (i have no errors) but i don't know the way to display in my view the specific result from :
if(!error) {
Ready.set(result)
}
Transactions are contained in tx.txs, iterates through that.
Template.wallet.helpers({
addrTxs: function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx);
return tx.txs;
});
}
});
You're right, you need to use the sessions variables with async call.
First, call method on created :
Template.wallet.created = function () {
Meteor.call('getWalletPreviousTx', function(err, tx) {
console.log(tx.txs);
Session.set('tx', tx.txs);
});
};
Helper should look like this :
Template.wallet.helpers({
addrTxs: function () {
return Session.get('tx');
}
});

How to update nested user collection

I've been trying to figure this out for quite a while now and feel like I've tried everything.
I have a nested collection under users called details. I had no issues updating the details fields from the client but I obviously want to run the updates through the server for security.
Here's my server code:
//server code
Meteor.methods({
updateProfile : function() {
Meteor.users.update({ _id: Meteor.userId() }, { $set: { "details.phoneNumber" : phoneNumber }
});
}
});
And my client code:
Template.userEdit.events({
'submit updateProfile' : function(e, t){
e.preventDefault();
var firstName = e.target.phoneNumber;
Meteor.call('phoneNumber');
}
});
For now I am publishing/subscribing to the entire users collection:
// Server
Meteor.publish("allUserData", function () {
return Meteor.users.find();
});
// Client
Tracker.autorun(function () {
Meteor.subscribe("allUserData");
});
Your server method is called "updateProfile", but you call "phoneNumber" on the client. Meteor methods are called as follows, in your case:
Meteor.call("updateProfile", phoneNumber);
And your server method must accept an argument as input:
Meteor.methods({
updateProfile : function(phoneNumber) {
//...
}
});

Categories

Resources