How Do I Nest Meteor Spacebars Templates? - meteor

I'm using a package called AutoForm.
{{> afQuickField name="propertyInfo.zipcode" placeholder="XXXXX" class="form-control track-order-change"}}
It basically renders a label and input element.
I have a session variable:
Session.set("zipcode", //something dynamic);
I have a registered helper:
Handlebars.registerHelper("zipcode", function(){
return Session.get("zipcode");
})
I would like something like this to work:
{{> afQuickField name="propertyInfo.zipcode" value="{{zipcode}}" placeholder="XXXXX" class="form-control track-order-change"}}

First fix you global helper to read:
Template.registerHelper("zipcodeHelper", function(){
return Session.get("zipcode");
})
Then fix the afQuickField a little:
{{> afQuickField value=zipcodeHelper class="form-control track-order-change"}}
Refer to this GH issue: https://github.com/aldeed/meteor-autoform/issues/210

Related

Meteor - event on {{if currentUser}} content loaded

I have a template
{{#if currentUser}}
<input id="datetimepicker" type="text" >
{{/if}}
I want do add
$('#datetimepicker').datetimepicker();
But in methods of template:
onCreated
onRendered
content of {{#if currentUser}} is not accessible because collection with user is loaded after template. I can use setTimeout, but this is non stable solution. I can to type in template
{{#if currentUser}}
<input id="datetimepicker" type="text" >
<script>
$('#datetimepicker').datetimepicker();
</script>
{{/if}}
but this is not elegant.
How to catch rendering of content in block {{if currentUser}} in correct way? Or maybe should I not use this syntax generally and there is other manner of checking is user is loaded. If yes, link to proper tutorial please.
The way to do this is to make the content of the if another template, and then use the onRendered or onCreated methods of that template.
{{#if currentUser}}
{{> datePicker}}
{{/if}}
...
<template name="datePicker">
<input id="datetimepicker" type="text" >
</template>
JS:
Template.datePicker.onCreated(() => {
// something
});
#Christian Fritz's answer works well.
In case you don't want to create a new template because of some other issues, you can also try this in the onRendered callback:
Tracker.autorun(function() {
if ($('#datetimepicker')[0]) {
$('#datetimepicker').datetimepicker();
}
});

How can I style an autoform in Meteoric?

{{#autoForm schema="asdf" id="sdfg" type="method" meteormethod="meth"}}
<fieldset>
{{> afQuickField name="startLocation"}}
{{> afQuickField name="destination"}}
{{> afQuickField name="date"}}
{{> afQuickField name="departureTime"}}
{{> afQuickField name="returnTime"}}
{{> afQuickField name="seats" type="number"}}
</fieldset>
<button type="submit" class="btn btn-primary">submit<button>
{{/autoForm}}
The above code generates a form in my Meteor app, however it looks pretty bad (or at least, non-intuitive):
I don't know why this is. In the examples (1, 2) I'm looking at, the form renders in a much more sensical way. How can I get the afQuickField to show the label and the input on separate lines, or at least in another way that makes sense?

Meteor Users: add user by admin user only

I'm using the useraccounts package in my Meteor app. I want an admin to be able to add a new user (and disable signing up through the frontend). Therefore, I have added a Collection with a SimpleSchema as per the suggestion of meteor-collection2. I'm alos using AutoForm to create an 'Add user' page.
<template name="addCustomerProfile">
<div class="container">
<h1>Edit document</h1>
{{#if isReady 'updateCustomerProfile'}}
{{#autoForm collection="Users" id="userForm" type="insert" }}
<fieldset>
{{> afQuickField name='emails.0.address'}}
{{> afQuickField name='emails.0.verified'}}
{{> afQuickField name='services.password'}}
{{> afQuickField name='username'}}
{{> afQuickField name='profile.firstName'}}
</fieldset>
<button type="submit" class="btn btn-primary">Add User</button>
{{/autoForm}}
{{else}}
Nothing
{{/if}}
</div>
</template>
I can add users whenever the 'services.password' is not added to the form, but obviously no default password is set for the user in the Mongo database in that case. How can I add a field so the admin can set a default password for that user (which the user will then be able to change later on).
Why not just forbidClientAccountCreation and sendEnrollmentEmail?
Accounts.config({
forbidClientAccountCreation: true
});
Meteor.methods({
'inviteUser': function (doc) {
check(doc, YourForm);
let userId = Accounts.createUser(doc);
Accounts.sendEnrollmentEmail(userId);
}
});

Meteor Flow Router issue with update

I have a Meteor app and I'm transitioning from IronRouter to FlowRouter. So far so good, but there are aspects I don't understand yet.
I have a route as follows:
FlowRouter.route('/documents/:docId/edit', {
name: 'documentEdit',
subscriptions: function (params, queryParams) {
this.register('documentEdit', Meteor.subscribe('documentSingle', params.docId));
},
action: function (params, queryParams) {
BlazeLayout.render('layout', { top: 'header', main: 'documentEdit' });
},
});
First option:
Then I also have a template:
<template name="documentEdit">
<div class="container">
<h1>Edit document</h1>
{{#if isReady 'documentEdit'}}
{{#autoForm collection="Documents" doc=this id="documentForm" type="update" meteormethod="documentUpdateMethod"}}
<fieldset>
{{> afQuickField name='title'}}
{{> afQuickField name='content' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Update</button>
<a class="btn btn-link" role="button" href="{{pathFor 'documentsList'}}">Back</a>
{{/autoForm}}
{{/if}}
</div>
</template>
with a template helper as follows:
Template.documentEdit.helpers({
isReady: function(sub) {
if(sub) {
return FlowRouter.subsReady(sub);
} else {
return FlowRouter.subsReady();
}
}
});
This is as it is mentioned here, but I'm not getting the values pre-filled in the textboxes on the UI (which is normal when editing fields).
Second option:
When I do the following it works and I don't really understand why it works (found it browsing in different forums and tried it out):
<template name="documentEdit">
<div class="container">
<h1>Edit document</h1>
{{#with getDocument }}
{{#autoForm collection="Documents" doc=this id="documentForm" type="update" meteormethod="documentUpdateMethod"}}
<fieldset>
{{> afQuickField name='title'}}
{{> afQuickField name='content' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Update</button>
<a class="btn btn-link" role="button" href="{{pathFor 'documentsList'}}">Back</a>
{{/autoForm}}
{{/with}}
</div>
</template>
and the helper:
Template.documentEdit.helpers({
getDocument: function () {
return Documents.findOne();
}
});
So the questions are:
for the 1st option: any idea why it does not work. I would prefer that one as it's the documented way of doing things
for the 2nd option: not sure why I need (in the template helper) to do a Document.findOne() without even having to pass the id of the doc I want to edit:
You want to do template level subscriptions with Flow Router, that's one of the primary pattern changes.
So you'd do:
Setup the subscription at the template level. Autorun so it'll resubscribe on route changes.
Template.documentEdit.onCreated(function() {
var self = this;
this.autorun(function() {
var docId = FlowRouter.getParam('docId');
self.subscribe('documentSingle', docId));
};
};
Setup the template helper to pick up from the route, and grab the id and populate the helper/document.
Template.documentEdit.helpers({
getDocument: function () {
var docId = FlowRouter.getParam('docId');
var doc = Documents.findOne(docId) || {};
return doc;
}
});
Do a template level load check and if it's there render it, otherwise show loading...
<template name="documentEdit">
<div class="container">
<h1>Edit document</h1>
{{#if Template.subscriptionReady}}
{{#with getDocument }}
{{#autoForm collection="Documents" doc=this id="documentForm" type="update" meteormethod="documentUpdateMethod"}}
<fieldset>
{{> afQuickField name='title'}}
{{> afQuickField name='content' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Update</button>
<a class="btn btn-link" role="button" href="{{pathFor 'documentsList'}}">Back</a>
{{/autoForm}}
{{/with}}
{{else}}
Loading...
{{/if}}
</div>
</template>
Not knowing how this worked, seeing that all the tutorials I have read that deals with update used Iron router, I have spent 7 days worth of trying retrying, looking through others code, reading tutorials. Happy it now works.

How to render a Meteor Template from Collection of Template names?

I have three simple Templates in Meteor, and a Collection on the server with any combination of their names. I want to be able to render these templates dynamically based on which of their names are in the Collection.
Currently I am trying to accomplish this by using the client to subscribe to the Collection, and access the names through a template function. Unfortunately, if I try to run ">" on the names, Meteor attempts to render the variable name instead of the Template pointed to by its value.
So instead of rendering the html in template1, template2, and template3, the output is merely their names on the page: "template1 template2 template3".
Here is the code I've been using, I hope there's a way to solve my issue without having to run Meteor.render manually.
Server js:
TemplatesToRender = new Meteor.Collection("templatesToRender");
TemplatesToRender.insert({templateName: "template3"});
TemplatesToRender.insert({templateName: "template2"});
Client html:
<body>
{{#each templatesToRender}}
{{> templateName}} // meteor trying to render a template
// called "templateName" instead of the
// variable inside templateName.
{{/each}}
</body>
<template name="template1">
<span>Template 1</span>
</template>
<template name="template2">
<span>Template 2</span>
</template>
<template name="template3">
<span>Template 3</span>
</template>
You can make a render helper:
Handlebars.registerHelper('render', function(name, options) {
if (Template[name])
return new Handlebars.SafeString(Template[name]());
});
And use it with
{{render templateName}}
You might want to try this
in your html
<body>
{{> templateToRender}}
</body>
<template name="templateToRender">
{{! use below to detect which template to render}}
{{#if templateName "template1"}}
{{> template1}}
{{/if}}
{{#if templateName "template2"}}
{{> template3}}
{{/if}}
{{#if templateName "template3"}}
{{> template3}}
{{/if}}
</template
<template name="template1">
<p>this is template1</p>
</template>
<template name="template2">
<p>this is template2</p>
</template>
<template name="template3">
<p>this is template3</p>
</template>
in your script
Template.templateToRender.templateName = (which) ->
# if user have a field like templateName you can do things like
tmplName = Meteor.user().templateName
# Session.equals will cause a template render if condition is true.
Session.equals which, tmplName
Meteor 1.0 just came out today, and I just want to update this for 2014 :)
https://docs.meteor.com/#/full/template_dynamic
{{> Template.dynamic template=template [data=data] }}
Sample Usage:
{{#each kitten}}
{{> Template.dynamic template=kitten_type data=this }}
{{/each}}

Resources