Meteor Conditionally displaying nested templates - meteor

I have a template with several sub nested templates which should conditionally show based on the data saved in TemplateC collection as shown below, so I used the if condition in my template as shown below, but I am always having all sub templates displayed despite if the condition return true or false. Can someone please check my code and tell me what I am missing here? Thanks
var templateArray = ['false', 'false'];
Template.formBuilderPreview.created = function() {
var cursor = TemplatesC.find({}, { sort: { templateCode: 1 }});
if (!cursor.count()) return;
cursor.forEach(function (row) {
//only case 1 return in the switch below as case 2 never exist
switch(row.templateCode) {
case 1: templateArray[0] = true; break;
case 2: templateArray[1] = true; break;
default: templateArray[0] = true;
}
});
};
Template.formBuilderPreview.helpers({
template1box: function(){
console.log(templateArray[0]); //This returns true
return templateArray[0];
},
template2box: function(){
console.log(templateArray[1]); //This returns false
return templateArray[1];
}
});
Template:
<template name="formBuilderPreview">
<div id="fullpage">
{{#if template1box}}
{{> temp01}}
{{/if}}
{{#if template2box}}
{{> temp02}}
{{/if}}
</div>
</template>

You defined an array of strings, which I believe is causing the trouble, so I suggest you change
var templateArray = ['false', 'false'];
to
var templateArray = [false, false];
and it will work smoothly

Put that helpers together.
Template.formBuilderPreview.helpers({
template1box: function(){
if(templateArray[1]){
return true;
}else{
return false;
}
});
Now the Template should look like this.
<template name="formBuilderPreview">
{{#if template1box}}
<!-- If helper return TRUE this temp01 will be showed. -->
{{> temp01}}
{{else}}
<!-- If helper return FALSE this temp01 will be showed. -->
{{> temp02}}
{{/if}}
</template>
you get the idea with the helper, make it only on 1 helper, retiring true/false.

Related

Reuse Meteor template as inclusion with different helpers

I'd like to re-use a Meteor template as an inclusion (i.e. using {{> }}) in two different contexts. I know I can pass in different data with the inclusion by using {{> templateName data1=foo data2=bar}}, but I'm struggling to figure out how I can provide different helpers based on the context. Here's the template in question:
<template name="choiceQuestion">
<div class="choice-grid" data-picks="{{numberOfPicks}}" data-toggle="buttons">
{{! Provide for the user to make multiple selections from the multiple choice list }}
{{#if hasMultiplePicks}}
{{#unless canPickAll}}<span class="help-block text-center">Pick up to {{numberOfPicks}}</span>{{/unless}}
{{#each choices}}
<label class="btn btn-default"><input type="checkbox" class="choice" name="{{this}}" autocomplete="off" value="{{this}}" checked="{{isChecked}}"> {{this}}</label>
{{/each}}
{{/if}}{{! hasMultiplePicks}}
{{#if hasSinglePick}}
{{#each choices}}
<label class="btn btn-default"><input type="radio" class="choice" name="{{this}}" id="{{this}}" autocomplete="off" value="{{this}}" checked="{{isChecked}}"> {{this}}</label>
{{/each}}
{{/if}}{{! hasSinglePick}}
</div>
</template>
and here's how I've reused it:
{{> choiceQuestion choices=allInterests picks=4}}
The key component of the template is a checkbox. In one context, it will never be checked. In another, it may be checked based on the contents of a field in the user document. I've added checked={{isChecked}} to the template. I've read this boolean attribute will be omitted if a falsey value is returned from the helper which should work well for my purposes.
The template's JS intentionally does not have an isChecked helper. I had hoped I could provide one on the parent where the template is included in the other context in order to conditionally check the box by returning true if the checked conditions are met, but the template doesn't acknowledge this helper.
Here's the template's JS:
Template.choiceQuestion.helpers({
hasSinglePick: function() {
return this.picks === 1;
},
hasMultiplePicks: function() {
return this.picks > 1 || !this.picks;
},
numberOfPicks: function() {
return this.picks || this.choices.length;
},
canPickAll: function() {
return !this.picks;
},
});
and the parent's JS:
Template.dashboard.helpers({
postsCount: function() {
var count = (Meteor.user().profile.posts||{}).length;
if (count > 0) {
return count;
} else {
return 0;
}
},
isChecked: function() {
return (((Meteor.user() || {}).profile || {}).contentWellTags || []).indexOf(this) > -1 ? 'checked' : null;
}
});
Template.dashboard.events({
'click .js-your-profile-tab': function(){
facebookUtils.getPagesAssumeLinked();
}
});
I've tried a few other approaches as well. I tried passing the helper to the template along with the other context (i.e. {{> templateName data1=foo data2=bar isChecked=isChecked}}. This kinda works, but it calls the helper immediately. This breaks these since I need to use a value from the context to determine what to return from my helper. Since this value doesn't exist when the function returns, the function always returns undefined.
If I return a function from this helper rather than the value and then pass the helper into the template inclusion along with the data context, I get better results. In fact, my console logs show the desired output, but I still don't end up with the checked box I expect.
Here's what that looks like. Returning a function:
isChecked: function() {
var self = this;
return function() {
return (((Meteor.user() || {}).profile || {}).contentWellTags || []).indexOf(this) > -1 ? 'checked' : null;
};
}
and passing that to the template:
{{> choiceQuestion choices=allInterests picks=4 isChecked=isChecked}}
Is there an established pattern for overriding template helpers from the parent or for including helpers on the parent that are missing from the child template? How can I achieve this?

if else in handle bar template

In need to check this scenario using handle bar templates
if(data.Id==1 && Isreal==false)
{
//`enter code here
}
else if(data.id==2 && IsReal==true)
//other html
else
`//enter code here`last html
How can I do that, I tried using helper but it is not working in my case
Best practice is to not do any business logic in the template but instead do it before and pass it through the context into the template.
i.e.
var context = {
dataOneNotReal = data.Id==1 && Isreal==false,
dataTwoIsReal = data.id==2 && IsReal==true
};
then in the template
{{#if dataOneNotReal}}
// code
{{else}}
{{#if dataTwoIsReal}}
// code
{{else}}
// code
{{/if}}
{{/if}}

Rendering Template in Meteor and Iron Router depending on value in document

I am trying to render a template depending on a value of a field in a document.
I tried using a switch case in a helper but the return value comes out incorrect.
units_list.html
<template name="unitsList">
{{#each units}}
{{> unitItem}}
{{/each}}
</template>
units_list.js
Template.unitsList.helpers({
units: function() {
return Units.find({}, {sort: {name: 1}});
}
});
unit_item.html
<template name="unitItem">
{{name}}
</template>
unit_item.js
Template.unitItem.helpers({
unitType: function() {
var unitType = this.unitType;
switch(unitType){
case 'first': return "{{pathFor 'unitPageFirst'}}";
case 'second': return "{{pathFor 'unitPageSecond'}}";
}
}
});
I'm either going about this the wrong way or missing something elementary...
I've cut out a lot of code to focus on the problem.
Any ideas on how to get this working, or any suggestions on how to do it better?
You can't return uncompiled Spacebars strings from JS at execution time.
You can either use Router.path to get the path for your routes within your template helper :
Template.unitItem.helpers({
unitType: function() {
var unitType = this.unitType;
switch(unitType){
case 'first':
return Router.path('unitPageFirst', this);
case 'second':
return Router.path('unitPageSecond', this);
}
}
});
Or you can use plain Spacebars by declaring template helpers to check against the unitType.
HTML
<template name="unitItem">
{{#if unitTypeIs 'unitTypeFirst'}}
{{name}}
{{/if}}
{{#if unitTypeIs 'unitTypeSecond'}}
{{name}}
{{/if}}
</template>
JS
Template.unitItem.helpers({
unitTypeIs: function(unitType){
return this.unitType == unitType;
}
});
Have a look at Rendering Templates in the Iron-router guide, specifically the this.render('xyz'); statement
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#rendering-templates

Exception in template helper: Error: Can't use $ on template instance with no DOM

Anyone run into this issue using a #with?
// Code in the calling template, Helper here just used to pass parameters a sub template
{{#with inputControlCheckboxHelper "middleName" "Middle Name" "" "middleNameDNA" "Address" "Alexander"}}
{{> inputControlCheckbox}}
{{/with}}
// Just passing in parameters with this helper
Template.registerHelper("inputControlCheckboxHelper",
function (inputName, inputTitle, inputSubTitle, checkboxName, templateName, inputPlaceHolder) {
return {
fieldName: inputName,
title: inputTitle,
subTitle: inputSubTitle,
checkbox: checkboxName,
template: templateName,
placeHolder: inputPlaceHolder
};
});
// The sub template, this calls another helper
<template name="inputControlCheckbox">
{{#with shouldBeDisabled template checkbox}}
{{> afFieldInput name=../fieldName}}
{{/with}}
{{> afFieldInput name=checkbox type="boolean-checkbox"}}
</template>
// The template to check if the input above should be disabled.
Template.registerHelper("shouldBeDisabled", function (formName, checkBoxName) {
var checkBox = AutoForm.getFieldValue(formName, checkBoxName);
if (checkBox === true) {
return {disableMe: true, notApplicable: "N/A"};
}
else if (checkBox === false) {
return {disableMe: false, notApplicable: ""};
}
else if (checkBox === "") {
return {disableMe: false, notApplicable: ""};
}
});
In the Chrome console, the stack trace looks like so:
If I remove the {{#with shouldBeDisabled template checkbox}} line, I get no exception. Also, even with the exception, everything renders find and the checkbox works with the input.
I'm using Iron Router 1.0.1, Meteor 1.0, and Autoform 4.0.1
Update to Autoform 4.0.2 solved the issue.

Template reuse in meteor

I'm trying to reuse some control elements in my Meteor app. I'd like the following two templates to toggle visibility and submission of different forms.
<template name='addControl'>
<img class='add' src='/images/icon-plus.png' />
</template>
<template name='okCancelControl'>
<img class='submit' src='/images/icon-submit.png' />
<img class='cancel' src='/images/icon-cancel.png' />
</template>
I'll call these templates in another:
<template name='insectForm'>
{{#if editing}}
<!-- form elements -->
{{> okCancelControl}}
{{else}}
{{> addControl}}
{{/if}}
</template>
editing is a Session boolean.
What's a good way to wire up the controls to show, hide and "submit" the form?
The main problem is finding the addInsect template (where the data is) from the control templates (where the "submit" event fires). Here's what I did:
First, the controls:
<template name='addControl'>
<section class='controls'>
<span class="add icon-plus"></span>
</section>
</template>
<template name='okCancelControl'>
<section class='controls'>
<span class="submit icon-publish"></span>
<span class="cancel icon-cancel"></span>
</section>
</template>
Now the javascripts. They simply invoke a callback when clicked.
Template.addControl.events({
'click .add': function(event, template) {
if (this.add != null) {
this.add(event, template);
}
}
});
Template.okCancelControl.events({
'click .cancel': function(event, template) {
if (this.cancel != null) {
this.cancel(event, template);
}
},
'click .submit': function(event, template) {
if (this.submit != null) {
this.submit(event, template);
}
}
});
I then connected the callbacks using handlebars' #with block helper.
<template name='addInsect'>
{{#with controlCallbacks}}
{{#if addingInsect}}
<section class='form'>
{{> insectErrors}}
<label for='scientificName'>Scientific Name <input type='text' id='scientificName' /></label>
<label for='commonName'>Common Name <input type='text' id='commonName' /></label>
{{> okCancelControl}}
</section>
{{else}}
{{> addControl}}
{{/if}}
{{/with}}
</template>
And the corresponding javascript that creates the callbacks relevant to this form.
Session.set('addingInsect', false);
Template.addInsect.controlCallbacks = {
add: function() {
Session.set('addingInsect', true);
Session.set('addInsectErrors', null);
},
cancel: function() {
Session.set('addingInsect', false);
Session.set('addInsectErrors', null);
},
submit: function() {
var attrs, errors;
attrs = {
commonName: DomUtils.find(document, 'input#commonName').value,
scientificName: DomUtils.find(document, 'input#scientificName').value
};
errors = Insects.validate(attrs);
Session.set('addInsectErrors', errors);
if (errors == null) {
Session.set('addingInsect', false);
Meteor.call('newInsect', attrs);
}
}
};
Template.addInsect.addingInsect = function() {
Session.get('addingInsect');
};
Template.addInsect.events = {
'keyup #scientificName, keyup #commonName': function(event, template) {
if (event.which === 13) {
this.submit();
}
}
};
In the submit callback I had to use DomUtils.find rather than template.find because template is an instance of okCancelControl, not addInsect.
You can use Session for this. You Just need a template helper that returns a boolean flag that indicates whether you are editing the form fields. And manipulate the DOM based on the Session value set by this template helper.
Assume you have one text input, now when you are entering text in it, set the Session flag as true. This will trigger the helper to return true flag, Based on that, one of your two templates will be rendered in the DOM.
The isEditing is the helper that triggers whenever you change the Session value.
This helper function is the main part here, it returns true/false based on the session value you have set.
Template.insectForm.isEditing = function(){
if(Session.get('isEditing')){
return true;
}
else{
return false;
}
}
Remember to set the Session to false at the start-up as:
$(document).ready(function(){
Session.set('isEditing', false);
})
This will render the default add template in the html, Now when you click on ADD, you need to display another template, for that, set Session to true as:
'click .add' : function(){
Session.set('isEditing', true);
}
Accordingly when you click on CANCEL, set the session to false, this will make the isEditing to return false and the default add template will be displayed.
So your complete html will look something like this:
<template name='insectForm'>
{{#if isEditing}}
<!-- form elements -->
<input type="text" id="text" value="">
{{> okCancelControl}}
{{else}}
{{> addControl}}
{{/if}}
</template>
<template name='addControl'>
<img class='add' src='/images/icon-plus.png' />
</template>
<template name='okCancelControl'>
<img class='submit' src='/images/icon-submit.png' />
<img class='cancel' src='/images/icon-cancel.png' />
</template>
[UPDATE]
To get the instance of the template, you'll need to pass the additional parameter in the event handler that represents the template.
So update your event handler as:
Template.insectForm.events = {
'click .submit' : function(event, template){
//your event handling code
}
}
The parameter template is the instance of the template from which the event originates.
Note that, although the event fires form the image that is inside the okCancelControl template, the parameter will still contain the instance of the insectForm template. This is because we are calling the event handler as Template.insectForm.events = {} .
Also see this answer for template instances.

Resources