How to chain #has functional helper for {{else has}} - handlebars.js

I am trying to achieve {{else has}} same like "else if" in handlebars theme of ghost.io but I am facing an issue but it works as expected.
{{#primary_tag}}
{{#has slug="first-slug"}}
<h1>in slug 1</h1>
{{else has slug="slug-2"}}
<h2>In Slug 2</h2>
{{else}}
{{!-- TTC Modal - otherwise this --}}
<h3>In other slug</h3>
{{/has}}
{{/primary_tag}}
I am following the https://docs.ghost.org/api/handlebars-themes/helpers/has/ but there is no proper for {{else has}}

Related

Filter Ghost Homepage with specific tags

I use Ghost 3.0.2
I would like to limit first page (index.hbs) to display only posts with some tags.
I tryed without luck:
{{#foreach posts}}
{{#has tag="es"}}
{{> post}}
{{/has}}
{{/foreach}}
Current code is:
<!-- start content area -->
<div class="main-content-area">
<div class="container post-listing">
{{> loop}}
</div>
</div>

How to list pages in Ghost CMS?

I'm trying to show pages on my homepage.
In my home.hbs I have
{{!-- The tag above means: insert everything in this file
into the {body} of the default.hbs template --}}
{{#is "home"}}
{{#if #site.description}}
<header class="page-head">
<h2 class="page-head-title">{{#site.description}}</h2>
</header>
{{/if}}
{{/is}}
{{#get "posts" filter="page:true"}}
{{#foreach posts}}
{{title}}
<p>{{excerpt words="33"}}</p>
{{/foreach}}
{{/get}}
Nothing is listed on my homepage. This works for posts but not pages for some reason.
I have the article featured, and it has "Category" tag - is it possible to display these on the homepage?
You're almost there, try this:
{{#is "home"}}
{{#if #site.description}}
<header class="page-head">
<h2 class="page-head-title">{{#site.description}}</h2>
</header>
{{/if}}
{{/is}}
{{#get "pages" limit="all"}}
{{#foreach pages}}
{{title}}
<p>{{excerpt words="33"}}</p>
{{/foreach}}
{{/get}}
Hope this helps :)

Featured posts on front page

How can display featured posts at the top of the front page?
Followed by the remaining posts.
Currently they display at the top of each page of the pagination.
Here's my loop.hbs:
{{! Previous/next page links - only displayed on page 2+ }}
<div class="extra-pagination inner">
{{pagination}}
</div>
{{! This is the post loop - each post will be output using this markup }}
{{#foreach posts}}
{{#if featured}}
<article class="{{post_class}} featured">
<header class="post-header">
<h2 class="post-title">{{{title}}}</h2>
</header>
<section class="post-excerpt">
<p>{{excerpt words="26"}} <a class="read-more" href="{{url}}">»</a></p>
</section>
<footer class="post-meta">
{{#if author.image}}<img class="author-thumb" src="{{author.image}}" alt=" {{author.name}}" nopin="nopin" />{{/if}}
{{author}}
{{tags prefix="on"}}
<time class="post-date" datetime="{{date format='YYYY-MM-DD'}}">{{date format="DD MMMM YYYY"}}</time>
</footer>
</article>
{{/if}}
{{/foreach}}
{{! This is the post loop - each post will be output using this markup }}
{{#foreach posts}}
{{#unless featured}}
<article class="{{post_class}}">
<header class="post-header">
<h2 class="post-title">{{{title}}}</h2>
</header>
<section class="post-excerpt">
<p>{{excerpt words="26"}} <a class="read-more" href="{{url}}">»</a></p>
</section>
<footer class="post-meta">
{{#if author.image}}<img class="author-thumb" src="{{author.image}}" alt=" {{author.name}}" nopin="nopin" />{{/if}}
{{author}}
{{tags prefix="on"}}
<time clas s="post-date" datetime="{{date format='YYYY-MM-DD'}}">{{date format="DD MMMM YYYY"}}</time>
</footer>
</article>
{{/unless}}
{{/foreach}}
{{! Previous/next page links - displayed on every page }}
{{pagination}}
Here's my blog: http://netsca.pe/
The only featured post currently is How to Install Ghost on AWS | Amazon EC2 for free - the Complete Guide.
As you can see, it is displayed at the top of the third page of posts, as opposed to at the top of the front page.
I had a read of Stack Overflow: newest post with specific tag on the front page but still can't figure this out.
Also had a read through this: The Ghost Blogging Support Forum: Show Featured post first on index page
but still nowhere.
variations of {{get}} were not successful for me on the latest version of Ghost. What did work was:
<section id="main">
{{#foreach posts}}
{{#if featured}}
html for featured posts
{{/if}}
{{/foreach}}
<div>
{{#foreach posts}}
{{^if featured limit="2"}}
html for regular post loop
{{/if}}
{{/foreach}}
</div>
</section>
This displayed the featured posts on top while another separately styled loop of posts were displayed below.
Firstly credit to #subic from ghost.slack.com who kindly tested my theme and pointed me in the right direction.
After having a read of the lengthy discussion GitHub Ghost Issue: Query (get) helper #4439 recently closed, great news - helpers and filters are being added to Public API v1!
The {{#get}} helper #5619 has just been merged to master (still unstable), so the solution:
{{#get "posts" featured="true" as |featured|}}
{{#foreach featured}}
...
{{/foreach}}
{{/get}}

Iron-router's this.render function does not render

As the title says, this.render does not render a template it's provided with. This is the code in router.js:
Router.configure({
layoutTemplate: 'main'
});
Router.route('/', function(){
this.render('postsList');
});
The file containing the layout template, main.html:
<template name='main'>
<div class='container'>
<header class='navbar'>
<div class='navbar-inner'>
<a class='brand' href='/'>MyApp</a>
</div>
</header>
<div id='main' class='row-fluid'>
{{> yield}}
</div>
</div>
</template>
And the file containing the postsList template which is passed to this.render() function
<template name='postsList'>
<div class='posts'>
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
So when I go to localhost:3000/ the page displays only the main template and not the postsList template. However, there is no error, unless I completely remove Router.route(...), at which point it will display the standard 'route not found' error.
Also, I tried not using the global template, but a route template, by removing Router.configure(...) and adding this.layout('main') to Router.route(...). The browser then displays nothing.
Your code is perfectly fine. I also came across this issue. The iron:router package seems to be missing the ejson dependancy.
Add the ejson to your app and it should work.
meteor add ejson
I'm sure when iron:router is updated this will be resolved.

Can Meteor handle nested views?

I'm learning meteor, and finding all kinds of difficulties dealing with nested subviews. Since the application I want to write is full of them... that looks like a difficulty. I found this on github, as a readme for a Meteor project to try and deal with this problem.
"I've been playing around with Meteor for a couple weeks. The ease of setup and the powerful reactivity makes this something I want to stick with. I was however frustrated by the difficulty of programmatically configuring, instantiating, destroying and nesting subviews."
Is this an issue that can be handled in Meteor (without adding a lot of complicated work arounds) or should I look for a different platform ?
I love nesting templates. I get reliable results. I now program off a library of both templates and helper functions (usually for form elements) that compose html for me. HTML is a byproduct, and the files we call .html are really a javascript DSL.
There are many S.O. issues raised about insertions into sorted lists giving people problems. I haven't had time to look.
My rule of thumb: Meteor is (well) designed from the beginning to do this easily and reliably.
So far the harder thing to solve was when I added an accordion from foundation, and a refresh of the document led to its initial state (being all closed, or one open). I had to put code in that saved the current section, and code to re-assert that in the rendered callback for the template that used it.
Why not write a prototype of the nesting with just a field or two in places, and find what bothers you?
Here is a sample chain. You see all the nested templates. This template itself is running within multiple.
First template: called 'layout', suggested by iron router. Has basic page and menu. Main body is a yield, set by router. On a sample page, a route calls template 'availability'
<template name='availability'>
{{#each myAgents}}
<form class="custom" id="Agent_{{_id}}" action="">
<div id='availability' class="section-container accordion" data-section="accordion">
<section id="services">
<p class="title" data-section-title><a href="#">
Your Info
</a></p>
<div class="content" data-section-content>
{{>services}}
</div>
</section>
<section id="skills">
<p class="title" data-section-title><a href="#">
Skills
</a></p>
<div class="content" data-section-content>
{{>skills}}
</div>
</section>
<section id="sureties">
<p class="title" data-section-title><a href="#">
Sureties
</a></p>
<div class="content" data-section-content>
{{>sureties}}
</div>
</section>
<section id="time">
<p class="title" data-section-title><a href="#">
Time Available
</a></p>
<div class="content" data-section-content>
{{>time}}
</div>
</section>
<section id="schedule1">
<p class="title" data-section-title><a href="#">
Schedule 1
</a></p>
<div class="content" data-section-content>
{{>schedule}}
</div>
</section>
<section id="schedule2">
<p class="title" data-section-title><a href="#">
Schedule 2
</a></p>
<div class="content" data-section-content>
{{>schedule}}
</div>
</section>
<section id="distance">
<p class="title" data-section-title><a href="#">
Distance
</a></p>
<div class="content" data-section-content>
{{>distance}}
</div>
</section>
</div>
</form>
{{/each}}
</template>
sample further nest:
<template name='services'>
{{label_text fname='name' title='Agent Name' placeholder='Formal Name' collection='agent' passthrough='autofocus=autofocus ' }}
{{label_text fname='agentInCharge' title='Agent In Charge' placeholder='Owner' collection='agent' }}
{{label_text fname='phone' title='Phone Number(s)' placeholder='Include Area Code'collection='agent' }}
{{>gps }}
<h4>Not shared:</h4>
{{label_text fname='email' title='Email:' placeholder='you remain anonymous' collection='agent' }}
</template>
and label_text is a helper, learned from the https://github.com/mcrider/azimuth project:
generateField = (options) ->
options.hash.uniqueId = options.hash.fieldName + "_" + Math.random().toString(36).substring(7) if options.hash.template is "wysiwyg"
options.hash.id = options.hash.id or #_id
options.hash.value = options.hash.value or this[options.hash.fname]
# allow for simple params as default
options.hash.title = options.hash.title or options.hash.fname
options.hash.template = options.hash.template or "label_text"
options.hash.placeholder = options.hash.placeholder or options.hash.title
# compatible with old
options.hash.fieldName = options.hash.fieldname or options.hash.fname
options.hash.label = options.hash.label or options.hash.title
# FIXME: Return error if type not valid template
new Handlebars.SafeString(Template[options.hash.template](options.hash))
Handlebars.registerHelper "label_text", (options) ->
options.hash.collection = options.hash.collection or 'generic'
generateField.call this, options
I am fairly new to Meteor, but I found out really soon that I wanted nested views (aka dynamic includes or sub-templates). I'm not sure whether this is what you mean, but here is my solution.
I created the following handlebars helper, that can be used to create sub-templates:
Handlebars.registerHelper('subTemplate', function(container, property, context, options) {
if (container && container.hasOwnProperty(property)) {
var subTemplate = container[property];
if (typeof subTemplate === 'function') {
return new Handlebars.SafeString(subTemplate(context || this));
}
else if (typeof subTemplate === 'string') {
return new Handlebars.SafeString(Template[subTemplate](context || this));
}
}
});
It can be used inside something I call a generic template. For example to create a list:
<template name="item_list">
<ul class="items-list">
{{#each items}}
<li class="listview-item">
{{subTemplate .. 'listItem' this}}
</li>
{{/each}}
</ul>
</template>
Now invoking this generic template requires that a 'listItem' property is present within its context. This can be either a string with the name of the sub-template, or the inline definition of a sub-template. The example below shows both options:
<template name="my_list">
{{! First option, referring to the sub-template by name:}}
<div>
{{#with listData listItem="my_list_item"}}
{{> item_list}}
{{/with}}
</div>
{{! Second option, inlining the sub-template:}}
<div>
{{#with listData}}
{{#assignPartial 'listItem'}}
<span>{{name}}</span>
{{/assignPartial}}
{{> item_list}}
{{/with}}
</div>
</template>
<template name="my_list_item">
<span>{{name}}</span>
</template>
Template.my_list.listData = function() {
return {
items: collections.people.find()
};
};
The second option requires an extra handlebars helper.
Handlebars.registerHelper('assignPartial', function(prop, options) {
this[prop] = options.fn;
return '';
});
I made more of these kinds of useful helpers, at some point I will probably share them on GitHub.

Resources