← Previous: Pushing assets to the browser
Apostrophe pages are part of a "tree" in which every page is a child of another page, except for the home page. That makes it very easy to build navigation links for common cases.
OK, you can probably guess the URL for that! But let's ask Apostrophe:
<h2><a href="{{ data.home._url }}">{{ data.home.title }}</a></h2>
There are real advantages to doing it this way. If the site has a prefix
option, you'll still get the right URL. And the title of the home page can change.
"Why
_url
?" The URL isn't a permanent part of the page object that lives in the database. Anything that is dynamically set and not part of the database starts with_
, so it doesn't get accidentally stored back to mongodb.
Lots of sites have a row of "tabs" at the top. Want to display those no matter where in the site you are?
<ul class="tabs">
{% for tab in data.home._children %}
<li><a href="{{ tab._url }}">{{ tab.title }}</a></li>
{% endfor %}
</ul>
Now let's add a CSS class indicating the current tab (the one that is the current page, or an ancestor of it):
<ul class="tabs">
{% for tab in data.home._children %}
<li class="
{% if data.page and
(apos.pages.isAncestorOf(tab, data.page) or tab._id == data.page._id)
%}
current
{% endif %}
"><a href="{{ tab._url }}">{{ tab.title }}</a></li>
{% endfor %}
</ul>
Sometimes you'll want to display dropdown menus. Each menu represents a child of the home page, and each item on each menu represents a child of that page.
First, in app.js
, let's configure apostrophe-pages
to retrieve two levels of children when fetching ancestors of the current page:
modules: {
// ... other configuration ...
'apostrophe-pages': {
filters: {
// Grab our ancestor pages, with two levels of subpages
ancestors: {
children: {
depth: 2
}
},
// We usually want children of the current page, too
children: true
}
// other apostrophe-pages options like `types` ...
},
// ... other configuration ...
}
Now we can easily output all the markup we'd need for dropdown menus:
<ul class="tabs">
{% for tab in data.home._children %}
<li><a href="{{ tab._url }}">{{ tab.title }}</a>
{% if tab._children.length %}
<ul>
{% for child in tab._children %}
<li><a href="{{ child._url }}">{{ child.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
The current page is data.page
, and by default, data.page._ancestors
is available:
{% if data.page %}
<ul class="breadcrumbs">
{% for ancestor in data.page._ancestors %}
<li><a href="{{ ancestor._url }}">{{ ancestor.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
Always check whether
data.page
exists when using it in a layout template that might also be extended bylogin.html
,notFound.html
and other places where there is no CMS "page."
Want to list the ancestors of the current page along with their subpages? Sure:
{% if data.page %}
<ul class="accordion">
{% for ancestor in data.page._ancestors %}
<li><a href="{{ ancestor._url }}">{{ ancestor.title }}</a>
{% if ancestor._children.length %}
<ul>
{% for child in ancestor._children %}
<li><a href="{{ child._url }}">{{ child.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
That's another easy one:
{% if data.page %}
<ul class="children">
{% for child in data.page._children %}
<li><a href="{{ child._url }}">{{ child.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
"The page tree is very nice, but how do I build a custom navigation menu with hand-picked pages from all over the tree?" That's a good question. To accomplish it we'll create a custom widget in the next tutorial.