Meteor - Display the Email Address of the Logged In User - javascript

I am trying to display the email address of the logged in user with Meteor.
I am using the command Meteor.user().emails[0].address -- and this works sometimes only. Other times it is undefined. This is because sometimes the page renders before the User's collections is available.
However, I am using React and not blaze. Every solution online suggests using Meteor.subscribe() in the onCreated part of the template. But I cannot figure out React's equivalent and I cannot figure out how to wait for the User collection before rendering.

Updated to use Meteor.autorun which accepts a callback function that runs whenever Meteor's reactive sources update.
Meteor.subscribe accepts an onReady optional callback. I would attach to the componentWillMount lifecycle event on your React component, setup your meteor subscription, and cause a state change once onReady has fired. Here is some rough example code;
var Foo = React.createClass({
componentWillMount: function() {
var _this = this;
// Setup meteor subscription
Meteor.autorun(function () {
_this.setState({
user: Meteor.user(),
});
})
},
render: function() {
// Render nothing until we have a user
if (!this.state || !this.state.user) {
return null;
}
// Render the address when we have the user
return (
<div>{this.state.user.emails[0].address}</div>
);
}
});
Relevant docs: http://docs.meteor.com/api/pubsub.html#Meteor-subscribe

Related

What does unsubscribe() do in this firebase auth sample?

On this page https://firebase.google.com/docs/auth/web/google-signin#expandable-2 there is a code sample where a function calls itself (see text in bold below) -- I'm confused what this means, can anybody please shed some light -- why does unsubscribe call itself?
console.log('Google Auth Response', googleUser);
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = firebase.auth().onAuthStateChanged((firebaseUser) => {
unsubscribe();
Calling onAuthStateChanged() "adds an observer/listener for changes to the user's sign-in state" AND returns an unsubscribe function that can be called to cancel the listener.
So the goal of the following pattern
var unsubscribe = firebase.auth().onAuthStateChanged((firebaseUser) => {
unsubscribe();
// ...
});
is to listen only once for changes to the user's sign-in state. The first time the listener is triggered it calls the unsubscribe function, so it doesn't listen anymore.
As explained in the comment in the code you refer to, they use this pattern in order to make sure auth is initialized.
Note that one could have very well done:
var foo = firebase.auth().onAuthStateChanged((firebaseUser) => {
foo();
// ...
});

Meteor Tracker not receiving subscriptions automatically

I'm creating some templates using Template.onCreated, and am then using Tracker.autorun to make some subscriptions and then collect data from the Server and store them on the client's MiniMongo.
Then, I can leave said Template and eventually route myself back. However, I'm noticing that upon coming back, Blaze is not capturing my changes. When routing back, it seems that onRendered is called instead of onCreated. This makes sense, however, onRendered isn't quite reacting to all my data changes yet. I've noticed it's because minimongo doesn't actually have data in it for onRendered.
However, I've noticed it can get the object by refreshing the page (thus calling onCreated and subscribing again and getting a fresh set of data from the server) My workaround is to re-subscribe in onRendered, but I feel like i shouldn't have to do this because I already initially subscribed in OnCreated. Is this an issue with Meteor, is DDP just going slow?
Let's say I have some default generic collection called Objects.
const Objects = new Mongo.Collection("Objects");
So in my onCreated I subscribe to a collection as follows
Template.foo.onCreated(function () {
var self = this;
self.autorun(function () {
const objId= FlowRouter.getParam("id");
self.objectSubscription = Meteor.subscribe('obj', objId, {
onReady: function () {
},
onStop: function (error) {
if (error) {
alert('error')
}
}
});
Then in onRendered I have to hack it and unnecessarily re-subscribe because I don't have objId i.e. I can't just use Objects.find(),
Template.foo.onRendered(function () {
const objId= FlowRouter.getParam("id");
Meteor.subscribe('obj', objId, {
onReady: function () {
$('#obj').addClass('highlight');
},
onStop: function (error) {
if (error) {
alert('error');
}
}
});
//I feel like I should just be able to do
//const obj = Objects.findOne({_id:objId})
//$('#obj').addClass('highlight')
});
Any insights, why would I be losing data in minimongo? And is it bad practice to "re-subscribe"?
onCreated and onRendered aren't reactive, but template helpers are. So, to constantly detect changes in those two you'd have to create a reactive context and place it inside them which can be achieved using Tracker.autorun. Also, be advised that it's better to keep onRenderd for DOM manipulations and onCreated for subscriptions and creation of reactive variables.
You don't need double subscriptions to detect changes and IMO this is generally a bad practice.
Template.foo.onCreated(function onCreated() {
const self = this;
this.autorun(function() {
const id = FlowRouter.getParam('_id');
self.subscribe('obj', id);
});
});
Template.foo.onRendered(function onRendered() {
const self = this;
// this will run after subscribe completes sending records to client
if (self.subscriptionsReady()) {
// do whatever you want
$('#obj').addClass('highlight');
}
});

Check permissions before vue.js route loads

does anyone know how to check a user's permissions before a vue.js route is rendered? I came up with a partial solution by checking permissions in the created stage of a component:
created: function () {
var self = this;
checkPermissions(function (result) {
if(result === 'allowed') {
// start making AJAX requests to return data
console.log('permission allowed!');
} else {
console.log('permission denied!');
self.$router.go('/denied');
}
});
}
However, the issue is the entire page loads momentarily (albeit without any data) before the checkPermission() function gets activated and re-routes to /denied.
I also tried adding the same code in the beforeCreate() hook, but it didnt seem to have any effect.
Does anyone else have any other ideas? Note - the permissions vary from page to page.
Thanks in advance!
The thing you need is defined in Vue Router Docs as Data Fetching - https://router.vuejs.org/en/advanced/data-fetching.html
So, as docs says, sometimes you need to fetch data when route is activated.
Keep checkPermissions in created hook, and then watch the route object:
watch: {
// call again the method if the route changes
'$route': 'checkPermissions'
}
A maybe more handy solution would be move logic from created hook into separated method and then call it in hook and in watch object too, as well.(Using ES6 syntax bellow)
export default {
created() {
this.checkPermissions()
},
watch: {
'$route': 'checkPermissions'
},
methods: {
checkPermissions() {
// logic here
}
}
}

pusher subscription with React-native, setState update

I'm trying to implement function with Pusher-JS in a React-native app but having a difficult time to appropriately update the state of a variable in this app.
Out side of main class, I define
var pusher = new Pusher('xxxxxxxsome number and code');
Inside the main class component, I define a function
test() {
var channel = pusher.subscribe('test_channel');
console.log('ddddddd');
channel.bind('my_event', function(data) {
if (data != null) {
if (data.message != null){
console.log(data.message);
this.setState({
message_box: data.message
});
}
}
}.bind(this));
}
and I put test() under render() function like the below.
render() {
this.what();
...
The app freezes when I push a text message (from pusher testing server) to 'test_channel'(in the mobile app). When I see the log in Chrome console, the console.log('dddddd') and console.log(data.message) keeps being scrolled down very quickly ( seems like test() is re-rendered a lot ).
I tried to take test() outside of render() but I don't know how to separately put and update the state variable outside of main component.
Is there way that I can stabilize this function or way to setState outside of main component ( this )?
Please share any idea with me!
Best
Is your test function being called every time on render? Pusher#bind adds a new callback to its registry whenever it gets called. It could be that whenever a message comes in, this function is being called multiple times, leading to more callbacks in the registry.
Perhaps try binding to an event once, perhaps in getInitialState?

Clean up requests and callbacks when switching routes

I have a backbone app that loads some data from an API into a chart. This app has several tabs that can be navigated through to access these different charts, and every tab executes a route. Every chart is an instance of ChartView with the appropriate data put in.
I have a problem that is caused by some API calls that may take a while. When the requests takes too long, some users start to cycle quickly through the tabs, executing each route quickly after each other. This fires up all the collection fetches which eventually messes up the interface because some callbacks will do a bit of rendering.
So my question is, how can i make sure that every time a new route is loaded (even if it is done in quick succession) that all pending or started requests are stopped so no "request-success" callbacks are fired?
I would suggest, override Backbone.Views remove method. With regular stopListening, abort ajax calls, also set a flag like this.removed=true. In your render function check for removed flag, if present don't render. If click has been done very quickly, you may need to check it before making any calls.
Based on Ravi Hamsa's reply I implemented an object that is injected into each route that keeps the requests and whether or not the route is still relevant.
It looks like this:
var RouteContext = function RouteContext() {
this._xhrs = {};
this.stopped = false;
this.manageRequest = function(xhr) {
this.xhrs.push(xhr);
}
this.stop = function() {
this.stopped = true;
_.invoke(this.xhrs, 'abort');
}
}
I override the Backbone.Router route method like this:
route: function(route, name, callbackFactory) {
var callback;
if (_.isFunction(callbackFactory)) {
var context = new RouteContext();
callback = callbackFactory(context);
// When a new route is opened, this route should be stopped and all
// corresponding jqXHR's should be aborted.
App.mediator.on('tabClicked', function() {
context.stop();
});
} else {
callback = callbackFactory;
}
return Backbone.Router.prototype.route.call(this, route, name, callback);
}
I can now create a new route method with this context like this:
var routeFactory = function(routeContext) {
// Might do some route initialisation here.
return function() {
this.reset(routeContext);
// This function is the actual function that will be called when a route is triggered.
if (routeContext.stopped === false) {
myView.renderChart();
}
}
};
// Register the route on the router.
myRouter.route('route', 'name', routeFactory);
Because a route can be called multiple times I reset the RouteContext back to it's original state when the route is called again.
And in my route I keep checking everywhere I need to do rendering whether the routeContext.stopped is still false. If it is true I don't do the rendering.

Categories

Resources