Meter: embedding templates in Blaze - meteor

Using Bootstrap and Meteor / Blaze, I am trying to dynamically control the size of a template using a template helper. I'd like to have a button to switch between col-md-4 and col-md-12. The hard-coded column sizing looks like this:
<div class="panel-body">
<div class="row">
{{#each articles}}
<div class="col-md-4">
{{> article this}}
</div>
{{/each}}
</div>
I have a template helper that returns the div and found I needed a closing helper call, or Meteor could complain about an unbalanced <\div>. This seems a bit hacky.
Template.articles.helpers({
format: function() {
return '<div class="col-md-4">';
// return '<div class="col-md-12">';
},
end_format: function() {
return '</div>'
}
});
The markup is:
<div class="panel-body">
<div class="row">
{{#each articles}}
{{{format}}}
{{> article this}}
{{{end_format}}}
{{/each}}
</div>
</div>
But the div tags are returned closed and empty, with the markup I'd like enclosed underneath, as can be seen in this screen shot:

Don't return HTML from template helpers, there is usually a better way.
Why don't you return a dynamic class name from a template helper ?
HTML
<div class="panel-body">
<div class="row">
{{#each articles}}
<div class="{{columnSize}}">
{{> article this}}
</div>
{{/each}}
</div>
<button type="button" class="btn btn-primary js-toggle-column-size">Toggle column size</button>
</div>
ES2015
Template.articles.onCreated(function(){
this.largeColumns = new ReactiveVar(false);
});
Template.articles.helpers({
columnSize(){
const largeColumns = Template.instance().largeColumns.get();
return largeColumns ? 'col-md-12' : 'col-md-4';
}
});
Template.articles.events({
'click .js-toggle-column-size'(event, template){
const largeColumns = template.largeColumns.get();
template.largeColumns.set(!largeColumns);
}
});

Related

BlazeLayout+FlowRouter+Bootstrap not rendering where told to

I've tried half a dozen different ways to do this but i'm not sure what the issue is.
To start, here is a quick drawing of what im trying to accomplish:
What I want:
http://prntscr.com/br8xh6
whats happening:
http://prntscr.com/br8z8p
What seems to be happening is that my .row .full-row is being rendered twice, and the dynamic template is not being loaded into my <div class="col-md-10> as defined. Why would this be?
Heres my current code:
<body>
<div class="container full-container">
{{> navbar}}
{{> middle}}
</div>
</body>
<template name="navbar">
...
</template>
<template name="middle">
<div class="row full-row">
<div class="col-md-2 left-bar" style="background:#800000;">
{{> Template.dynamic template=sidebar}}
</div>
<div class="col-md-10">
{{> Template.dynamic template=content}}
</div>
</div>
<!-- </div> -->
</template>
<template name="leftbar">
<div class="row">
<div class="col-md-12">
{{> avatar size="large" shape="circle"}}
</div>
</div>
</template>
<template name="usercard">
<div class="col-md-4">
<div class="thumbnail thumb-dark">
<img src="default.png" alt="...">
<div class="caption">
<h3>Player name</h3>
<p>...</p>
Join
</div>
</div>
</div>
</template>
<template name="home">
<div class="row">
{{#each playerslooking}}
{{> usercard}}
{{/each}}
</div>
</template>
<template name="find_page">
<div style="height:150px;width:150px;background:blue;">hello</div>
</template>
JS:
FlowRouter.route('/', {
action: function() {
BlazeLayout.render("middle", {sidebar: 'leftbar', content: "home"});
}
});
FlowRouter.route('/find/:_id', {
name: 'postfind.show',
action: function() {
BlazeLayout.render('middle', {sidebar: 'leftbar', content: "find_page"});
}
});
I've refactored my code several times trying to debug this, as I'm not sure how BlazeLayout is suppose to work with nested templates.
All input appreciated, thanks.
Just in case, did you have a try at Blaze Layout root modification?
See: https://github.com/kadirahq/blaze-layout#set-different-root-node

iron:router's yieldTemplates not working

I'm trying to use iron:router's yieldTemplatesproperty to render multiple templates on the same layout.
According to this tutorial, we should be abble to do something like this:
template.html
<template name="complexLayout">
<div class="left">
{{> yield region="menu"}}
</div>
<div class="main">
{{> yield}}
</div>
<div class="bottom">
{{> yield region="footer"}}
</div>
</template>
route.js
this.route('home', {
path: '/',
layoutTemplate: 'complexLayout',
yieldTemplates: {
'myMenu': {to: 'menu'},
'myFooter': {to: 'footer'}
}
});
I tried to do it, but the yieldTemplates part doesn't work.
Here is the relevant code:
Router.js
Router.map(function() {
this.route('home', {
path: '/home',
controller: 'homeController'
});
});
Controllers.js
baseController = RouteController.extend({
layoutTemplate: 'baseLayout'
});
homeController = baseController.extend({
yieldTemplates: {
'homeNavTop': {to: 'top'}
}
});
Templates.html
<template name="baseLayout">
<main>
<!-- NAV TOP -->
<div id="nav-top" class="hide-on-large-only light-blue darken-3 white-text">
<div class="row nomargin valign-wrapper hide-on-large-only">
{{> yield region='top'}}
</div>
</div>
<!-- / NAV TOP -->
<!-- BODY -->
<div class="row nomargin">
<div class="col s12">
{{> yield}}
</div>
</div>
<!-- / BODY -->
</main>
</template>
<template name="homeNavTop">
<a href="#" data-activates="slide-out" class="menu button-collapse btn-flat waves-effect">
<i class="material-icons">menu</i>
</a>
</template>
As explained, the BODY part works fine. The top region remains empty.
I have no console errors at all.
Do you have any clue of what is wrong in my code?
Perhaps the syntax has changed since that tutorial was written, but according to the IronRouter guide you should be doing this:
{{> yield 'top'}}
rather than this
{{> yield region='top'}}

How Do I Get First Collection Element Using Spacebars {{#if}} Tag?

I am trying to set the first picture as the "item active" i an Bootstrap Carousel. So, is there a way to make the first element from an collection to be presented different from the rest?
{{#each pictures}}
{{#if #first}}
<div class="item active">
<img src="/pictures/{{fileName}}" alt="" />
</div>
{{else}}
<div class="item">
<img src="/pictures/{{fileName}}" alt="" />
</div>
{{/if}}
{{/each}}
The rendered page only display the content in the {{else}} statement.
Have tried using {{if #first}}, but it does not work for me.
This is pretty similar to the problem of needing an index in your template. You need to map over pictures and mark the one you need treated differently. For example:
Template.myPictures.helpers({
pictures: function() {
return Pictures.find().map(function(picture, index) {
if (index === 0)
picture.isFirst = true;
return picture;
});
}
});
You can then use isFirst in your template like this:
{{#each pictures}}
{{#if isFirst}}
<div class="item active">
<img src="/pictures/{{fileName}}" alt="" />
</div>
{{else}}
<div class="item">
<img src="/pictures/{{fileName}}" alt="" />
</div>
{{/if}}
{{/each}}
Note that CoffeeScript's # doesn't work in templates. To learn more about template contexts see this.
It's not exactly what you were asking but you could make the first item active using jQuery in the rendered callback.
Template.myPictures.rendered = function () {
this.$('.item').first().addClass('active');
};

Meteor 0.80 new template displaying only [object Object] on my app

This is all I see as rendered result: [object Object]
What do I have to modify?
My files:
layout.html
<template name="layout">
<div class="container">
<div class="row">
{{yield}}
</div>
</div>
</template>
post_page.html
<template name="postPage">
<div class="sidebar col-md-4">
{{#each posts}}
{{> postItem}}
{{/each}}
<a class="save-all" href="javascript:;"><span class="glyphicon glyphicon glyphicon-save"></span></a>
</div>
<div class="mainbar col-md-12">
{{> postSubmit}}
</div>
</template>
post_page.coffee
Template.postPage.helpers posts: ->
Posts.find {},
sort:
position: 1
routes.coffee
Router.configure layoutTemplate: "layout"
Router.map ->
#route "home",
path: "/"
template: "home"
#route "postPage",
path: "/posts/:_id"
data: ->
Posts.findOne #params._id
post.coffee
#Posts = new Meteor.Collection "posts"
With 0.8 you need to do: {{> yield}} instead of {{yield}}.
Yes, as of Blaze, as describe here and here you need to change the syntax of your template slightly:
layout.html
<template name="layout">
<div class="container">
<div class="row">
{{> yield}}
</div>
</div>
</template>
Router has been deprecated. Use Iron-Router from meteorite, refer to the docs
Router.map(function() {
this.route('postslist', {path: '/'})
//read the docs for your next routing needs
});
This is a similar post to this question

Dynamically set a CSS property based on a template value

Is it possible to dynamically set the text color of a input field based on a handlebars.js template value?
I am initially creating my html using this template:
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
{{> project}}
{{/each}}
</div>
Where projects is an object read from a db. The resulting html (what gets rendered on the page not what is in my html) for each project looks something like this:
<div class="project">
<span class="name">FOO</span>
<span class="status">OK</span>
</div>
<div class="project">
<span class="name">BAR</span>
<span class="status">NOTOK</span>
</div>
I would like to render this html with the colour of the OK & NOTOK text set dynamically.
I already have a handlebars helper function that will successfully return the correct colour code based on each option and I can call this using:
{{getStatusColor currentStatus}}
What I would like to do is put this function call directly into the css itself, a bit like:
font-color: {{getStatusColor currentStatus}}
But obviously this doesn't work. This function does feel like the right approach though but where can I use it to format the text correctly on the page?
Answering my own question: The template needed to be expanded (from {{> projects}}) to allow for conditional rendering.
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
<div class="project">
<span class="name">{{name}}</span>
<span class="status" style="color:{{getStatusColor status}}">{{status}}</span>
</div>
{{/each}}
</div>
For completeness, the helper function getStatusColor looks like this:
Handlebars.registerHelper('getStatusColor', function(status) {
switch (status) {
case "GOOD" : {
return 'green';
}
break;
case "BAD" : {
return 'red';
}
break;
default : {
...etc.;
}
});
UPDATE:
In the interests of honesty, I should confess I totally missed that I already had this expanded template in my code and that {{> projects}} was pointing to this. I should have just added the style="color:{{getStatusColor status}}" attribute directly into the referenced project template. So, as much for my benefit as others, the final, working, HTML:
<template name="foo">
<div class="board">
<div class="header">
<span class="name">Project</span>
<span class="status">Status</span>
</div>
{{#each projects}}
{{> project}}
{{/each}}
</div>
</template>
<template name="project">
<div class="project {{selected}}">
<span class="name">{{name}}</span>
<span class="status"style="color:{{getStatusColor status}}">{{status}}</span>
</div>
</template>

Resources