I am very new to Meteor, I have a simple problem that can't find a right answer too.
I want to show a component only if they are logged In.
I tried to do it this way
Template.newPost.rendered= function(){
if(Meteor.user()){
$('#submit-btn').show();
$('#submit-text').hide();
}
else{
$('#submit-btn').hide();
$('#submit-text').show();
}
}
but problem is it get rendered before the Meteor.user() get loaded.
I think I am doing this the hard way is there any reactive way to do this simpler? if not, how can I make this approach work?
Thanks
If you are using blaze, you can skip all that and just use the currentuser helper in your template like this:
{{#if currentUser}}
<button id="submit-btn">Click me</button>
{{else}}
<p id="submit-text">Please log in to submit</p>
{{/if}}
Related
This has been asked before however, I don't feel I've seen a suitable answer. I'm currently using {{ #if currentUser.emails.[0].verified }} show data {{else}} please verify email {{/if}} on the layout template check whether or not the user has verified their email. In this scenario, I get a flicker between the screens if the user has registered because meteor.user() hasn't loaded completely so currentUser.emails.[0].verified returns null and changes to true once it has loaded completely.
Is there a way I can wait for Meteor.userId to completely load before the template renders without using delay?
The meteor embedded "currentUser" helper can let you know when the user collection is ready:
{{#if currentUser}}
// Do my stuff
{{else}}
Checking... // You can also show a spinner image or GIF here
{{/if}}
You can force the Template.subscriptionsReady to wait for the Meteor.user() data (so that when the Template.subscriptionsReady is true, the currentUser logic is also up-to-date and won't change) by adding a stub subscription.
I added the following Subscription and then subscribed to this from the template:
Meteor.publish('userWait', function () {
return null;
});
Here's a more detailed description of why this issue was popping up:
When loading a template, if you're only relying native handler for currentUser - then currentUser will always initially load false (in the template logic) and then will load true once the data load is complete.
Adding logic to show a loading state that relies on Template.subscriptionsReady will only work if there is an additional Subscription for the template (Template.subscriptionsReady doesn't acknowledge the automatic subscriptions for the user data).
For me, this meant that the internal pages will always prompt a login before realizing that the user was already logged in ... which was an ugly UX.
Once I added a Subscription to the template, even though it returned nothing, then Template.subscriptionsReady would wait until Meteor.user() data was available before returning as true.
Typically, you can use Template.subscriptionsReady in your Template to wrap code that depends upon subscribed data. Since Meteor handles the publish/subscribe of currentUser automatically, I'm not sure if this method will work or not. Give it a try and let me know.
Example.
{{#if Template.subscriptionsReady}}
{{ #if currentUser.emails.[0].verified }} show data {{else}} please verify email {{/if}}
{{/if}}
What I have found to work well for me is to subscribe to the user in the wait in a waitOn function in iron router:
Router.route('/',{
waitOn: [
function() {
if (!Meteor.userId()) {
Router.go("/login");
}
return Meteor.subscribe('currUser');
},
],
...
})
Since my variables are not reactive and there are probably over 500 variables in my script, there is not feasable way I can make everything reactive right now.
So my question is, is there any way to make Iron Router refresh the current route/template when prompted? Right now, the only way I accomplish this is using document.location.reload(true);, but that is an ugly looking and very slow process.
Let's also say that I have a {{> yield}} element in my template: is there any way to just refresh that part without refreshing the entire page?
You probably need to define a reactive variable (Session or ReactiveVar) and change the state of that variable. On your template, make an if wrapping the part you need to refresh. When you change the state, the part inside the if will be refreshed.
helpers:
h_checkToRefresh: function() {
if (Session.get('count') > 0) return true;
else return false;
}
template
{{#if h_checkToRefresh}}
{{>yield}}
{{/if}}
I am currently using Meteor 0.9.2.2. I am trying to better understand how to build a form in Meteor + Famous without having to put each form element into a Famous surface.
I am using the "gadicohen:famous-views 0.1.7" and "mjnetworks:famous 0.2.2 "
I am using https://github.com/gadicc/meteor-famous-views and have looked at some of the samples of events. I can generate events on the view but seems to have lost the ability to generate events using Jquery (probably Famous alarm bells going off) for fields on the template.
(Note I fid try following What is a recommended way to get data into your meteor template from the front-end for a famous surface? but that just directed me to the examples I am following - sorry still stuck)
For example, if I wanted to have a "blur" event when a contenteditable field changed and used that to update the database, I am not sure how I do it.
BTW, I am bringing in the template via Iron-router:
this.route('someTemplate', {
path: '/',
});
Here's some sample of code of what I have been playing around with:
<template name="someTemplate">
{{#Scrollview target="content" size="[undefined,100]"}}
{{#Surface class="green-bg"}}
<h4 id="main-edit-title" class="editable" data-fieldname="title" data-resourceid="{{_id}}" contenteditable=true>Heading</h4>
<p id="main-edit-message" class="mediumEditable editable" data-fieldname="message" data-resourceid="{{_id}}" contenteditable=true>Summary</p>
{{/Surface}}
{{/Scrollview}}
</template>
Template.someTemplate.events({
'blur .editable': function (e) {
e.preventDefault();
//e.stopPropagation();
var item = $(e.currentTarget);
DO SOME UPDATE STUFF TO THE DATABASE
item.removeClass('resourceUpdated');
},
});
I looked at the 'famousEvents' too and could not seem to get that working. Ie no events fired and that would only be at the surface level, not the field level.
At the view level I was fine and code below worked fine:
Template.someTemplate.rendered = function() {
var fview = FView.from(this);
var target = fview.surface || fview.view._eventInput;
target.on('click', function() {
clickeyStuff(fview);
});
}
I tried the other variants from this page: https://famous-views.meteor.com/examples/events
So the core questions, I think, is: Do I have to move every form element to a Famous Surface? This would be a killer. I am hoping I can still use Jquery or access the DOM for stuff within the template. Note I do see stuff in the Famous FAQ http://famo.us/guides/pitfalls that says don't touch the DOM... so happy to find out how else I should be doing this???
I tried to make this clearer on the events example page, but I guess I'm still not there yet. I'll answer below but please feel free to chime in with how I can improve the documentation.
Inside of a Surface is basically regular Meteor. But outside of a Surface is the realm of famous-views. So you need to have a Meteor template inside of a Surface for events to attach themselves properly - and, as noted in the docs - that template needs to have at least one element in side of it to attach the events. So either (and in both cases, renaming the outer template wrapper but leaving Template.someTemplate.events as is):
<template name="someTemplateWrapper">
{{#Scrollview target="content" size="[undefined,100]"}}
{{#Surface class="green-bg"}}
{{> someTemplate}}
{{/Surface}}
{{/Scrollview}}
</template>
or simply:
<template name="someTemplateWrapper">
{{#Scrollview target="content" size="[undefined,100]"}}
{{>Surface template="someTemplate" class="green-bg"}}
{{/Scrollview}}
</template>
and then move all the Meteor stuff that needs events to it's own template where the events are handled:
<template name="someTemplate">
<h4 id="main-edit-title" class="editable" data-fieldname="title" data-resourceid="{{_id}}" contenteditable=true>Heading</h4>
<p id="main-edit-message" class="mediumEditable editable" data-fieldname="message" data-resourceid="{{_id}}" contenteditable=true>Summary</p>
</template>
Hope that makes sense, just rushing out... let me know if anything is not clear and I'll ammend the answer later.
I am using Meteor 0.5.2 and trying to solve what seems to me is an obvious pattern that should have an easy solution.
I have a template that should return different chunk of data in each of template instances.
For example - I have a template showing TV program - show by show.
Then I need to display two instances of the same template with different data - one with past shows and one with upcoming shows.
So I have a tv program template:
<template name="tv_program">
{{#each shows}}
...
</template>
Ideally I would like do something like:
{{> tv_program past_shows}}
...
{{> tv_program upcoming_shows}}
to pass a parameter to tv_program template instance that I can read from JavaScript and adjust the mongo queries.
Currently I have copy/pasted my template/js code and adjusted the mongo queries but there has to be a better way.
I looked into partials/helpers with arguments but that doesn't seem to be the solution to my problem.
Thanks, Vladimir
You're approaching the problem at the wrong level. Rather than trying to tell your code what to do from your templates, you should tell your template what to do from your code. For instance:
Template.past_shows.shows = function() { return shows(-1); }
Template.upcoming_shows.shows = function() { return shows(1); }
function shows(order) {
return Shows.find({}, {$sort: order});
}
<template name="past_shows">
{{#each shows}}
{{> show}}
{{/each}}
</template>
<template name="upcoming_shows">
{{#each shows}}
{{> show}}
{{/each}}
</template>
<template name="show">
<li>{{_id}}: {{name}}</li>
</template>
If you are using a state machine for your app, such as meteor-router, you can use one template and populate it with upcoming or past shows depending on app state.
On Meteor, I'd like to prefetch data. I know this is normally automatically done. But there is a small wait for some action.
For example, I put a jquery event and change a session variable. Minimongo don't have that datas and have to fetch them.
I'd like to make an animation during which I'm fetching data and at the end of the animation change the templates.
Is it possible? How mould you do that?
Thanks in advance.
The only way minimongo won't have your data is when your subscription changes. So you could do
Edit: Clearing it up
Meteor.autosubscribe(function() {
//ADD LOADING TO PAGE HERE (1)
page = Session.get('paging')
Session.set('Sess1', true)
Meteor.subscribe('testdata', page, function() {
//remove loading to page here (2)
Session.set('Sess1', false)
});
});
For the template it doesn't need to change. You could set a Session at (1) and set another at (2).
So
<template name="test">
{{#if Sess1}}
might be loading here
{{else}}
display the data here
{{/if}}
</template>