Closed avishwakarma closed 4 years ago
I think you definitely need to use renderData
approach for dynamic titles. But curious if you need to put quotes around the permalink: "/tags/{{ tag | slug }}/"
and possibly:
renderData:
title: "{{ tag }}"
Sorry to add noise, but what in the heck is renderData? I literally ran into this issue (doing a tags page) and couldn't get title to be set to the tag.
@cfjedimaster Per #941:
it should be noted that for some time the undocumented
renderData
feature has only been available on pagination templates.
And I vaguely recall @zachleat doing a PR for some work on it recently in #942.
There are a few other linked issues in the various bugs and cool info if you search around for them https://github.com/11ty/eleventy/search?q=renderdata+is%3Aissue&type=Issues
Ok, so far this isn't working for me. My tags.liquid is:
---
pagination:
data: collections
size: 1
alias: tag
filter:
- all
- posts
permalink: "tags/{{ tag | slug }}/"
layout: tag
renderData:
title: "{{ tag }}"
---
If I output title in my layout file, I get an empty string.
@cfjedimaster If you want some fun, light reading, check out #927.
I think the problem is that you're looping over an object
and it isn't handling it like you expect. Using an Object.keys()
filter might work for you. Or Liquidjs has a map
filter which may also work. I've also been struggling with dumping out objects when debugging liquid (Nunjucks has a handy dump(2)
filter which pretty prints everything, but I guess we need to roll that outselves in liquidjs).
If I get some time later today I'll poke at the tag archive stuff some more since it seems to be pretty common. We need to do a CFLib.org for eleventy snippets/filters.
Heh yeah. The Quick Tips in the docs are nice, but we need a cookbook to handle growth I think. I see elsewhere that Zach is doing some stuff with renderData that is launching soon, so for now I'm ignoring it I guess.
My gut instinct would be to create a collections.tags
collection in my .eleventy.js config file and do the filtering/sorting there, but not sure if all the automatically generated tags from the templates are created at that point of configuration.
I did file #952 for the overall issue of tag management is kinda tricky and easy to get lost in (for a common feature).
I got it working w/ Liquid, but I don't like my hacky solution: https://github.com/pdehaan/11ty-collection-tag-archive
{%- assign $title = title -%}
{%- if renderData.title -%}
{%- assign $title = renderData.title -%}
{%- endif -%}
— /src/_includes/layouts/base.html#L2-L5
Not sure why my or
operators weren't working, but I was suspecting that it's treating the empty title as an empty string, and then not counting that as falsy. I even tried a few things using the liquidjs default
filter, but that didn't seem to work either. I'd need to dig into raw liquidjs and see if I can reproduce it, or try shimming the old version of liquidjs (6.x in eleventy@0.10.0 with the newer liquidjs 9.x and see if that makes any difference).
Yeah, this feels... not right. I wouldn't have expected an empty string to be truthy (for an or
operator). And I definitely wouldn't expect the Boolean false to somehow be truthy. Unless I'm doing something very very wrong.
<p>A: <q>{{ "" or "(empty string)" }}</q></p>
<!--
actual: "",
expected: "(empty string)"
-->
<p>B: <q>{{ false or "Boolean false" }}</q></p>
<!--
actual: "false",
expected: "Boolean false"
-->
{ eleventy: '0.10.0', liquidjs: '6.4.3' }
OK, a bit deeper into it. Looks like it might have been a bug in liquidjs@6.4.3 (current version bundled with eleventy@0.10.0), but I'm unable to reproduce it in the latest liquidjs@9.8.0:
const assert = require("assert");
const pkg = require("liquidjs/package.json");
let engine;
if (pkg.version.startsWith("9")) {
// v9.8.0 (latest)
const { Liquid } = require('liquidjs');
engine = new Liquid({ strictFilters: true});
}
if (pkg.version.startsWith("6")) {
// v6.4.2 (eleventy @ 0.10.0)
const Liquid = require("liquidjs");
engine = Liquid({strict_filters: true});
}
main()
.catch(err => {
console.error(err.message);
process.exit(2);
});
async function main() {
console.log(`${pkg.name} @ v${pkg.version}`);
try {
const ex6 = await engine.parseAndRender(`{% assign name="" %}{{ name | default: "colin" }}`);
assert.strictEqual(ex6, "colin");
} catch (err) {
console.error(err.message);
process.exitCode = 1;
}
try {
const ex7 = await engine.parseAndRender(`{% assign name=false %}{{ name | default: "danny" }}`);
assert.strictEqual(ex7, "danny");
} catch (err) {
console.error(err.message);
process.exitCode = 1;
}
}
$ npm i liquidjs@6.4.3 -D
$ node index
liquidjs @ v6.4.3
Expected values to be strictly equal:
'' !== 'colin'
# Fails. Empty string seems to be truthy.
$ npm i liquidjs@latest -D
$ node index
liquidjs @ v9.8.0
# Passes. Empty string seems to be falsy, and it uses the default value of "colin" for the test.
Per liquidjs docs:
Truthy and Falsy. All values except
undefined
,null
,false
are truthy, whereas in Ruby Liquid all exceptnil
andfalse
are truthy. See #26.
Wiki is super explicit about the behavior, so not sure how I missed that: https://github.com/harttle/liquidjs/wiki/Truthy-and-Falsy
I think that my confusion is based on how it works as I expected in Nunjucks, but Liquidjs seemingly has different logic for whether 0
and ""
are truthy or not which was causing my brain to break down a bit while debugging this.
I think you definitely need to use
renderData
approach for dynamic titles. But curious if you need to put quotes around thepermalink: "/tags/{{ tag | slug }}/"
and possibly:renderData: title: "{{ tag }}"
Putting tag "{{ tag }}"
gives {{ tag }}
in the output. Not the actual tag :(
title: "{{ tag }}"
pagination:
data: collections
size: 1
alias: tag
filter:
- post
permalink: "/tags/{{ tag | slug }}/"
I got it working w/ Liquid, but I don't like my hacky solution: https://github.com/pdehaan/11ty-collection-tag-archive
{%- assign $title = title -%} {%- if renderData.title -%} {%- assign $title = renderData.title -%} {%- endif -%}
— /src/_includes/layouts/base.html#L2-L5
Not sure why my
or
operators weren't working, but I was suspecting that it's treating the empty title as an empty string, and then not counting that as falsy. I even tried a few things using the liquidjsdefault
filter, but that didn't seem to work either. I'd need to dig into raw liquidjs and see if I can reproduce it, or try shimming the old version of liquidjs (6.x in eleventy@0.10.0 with the newer liquidjs 9.x and see if that makes any difference).
This worked for me :) thanks
I'm almost convinced that this is a very bad idea, but I wrote my own Liquid or
filter which considers an empty string to be falsy so it can check for other values (similar to how Nunjucks behaves):
module.exports = eleventyConfig => {
eleventyConfig.addLiquidFilter("dump", require("util").inspect);
// Usage: `{%- assign $title = title | or: renderData.title, site.title -%}`
eleventyConfig.addLiquidFilter("or", (value="", ...values) => {
// prepend the `value` value at the front of the `values[]` array.
values.unshift(value);
return values.find(truthy);
});
// ...
eleventyConfig.addLiquidFilter("truthy", truthy);
eleventyConfig.addLiquidFilter("falsy", value => !truthy(value));
// ...
};
function truthy(value) {
if (value === 0) return true;
return Boolean(value);
}
Now, in my templates I can check an array of values until it finds something truthy:
{%- assign $title = title | or: renderData.title1, renderData.title2, renderData.title -%}
title
is truthy, return that.renderData.title1
is truthy, return that.renderData.title2
is truthy, return that.renderData.title
is truthy, return that,Array#find()
fails, and should return undefined, which is falsy.I did some quick tests and it should match the default liquidjs behavior outlined in https://github.com/harttle/liquidjs/wiki/Truthy-and-Falsy, with the exception of empty strings.
value |
truthy |
falsy |
---|---|---|
true |
✔️ | |
false |
✔️ | |
null |
✔️ | |
undefined |
✔️ | |
string |
✔️ | |
empty string |
✔️ | |
0 |
✔️ | |
integer |
✔️ | |
float |
✔️ | |
array |
✔️ | |
empty array |
✔️ |
OK, pushed my latest (but definitely not greatest) code to https://github.com/pdehaan/11ty-collection-tag-archive
src/posts/post-7.liquid and src/posts/post-8.njk show the different empty string truthy behavior between Liquidjs and Nunjucks. Not a bug, but a fine little gotcha.
Also shows my custom, hacky "or" filter in src/_includes/layouts/base.html (not to be confused with the standard "or" operator).
And if you look at src/pages/about.liquid, you can see my JavaScript front-matter example which loops over a bunch of values and prints a handy chart to match the order/tests in the liquidjs wiki.
Ah, I didn’t quite read every comment here but from what I could glean this is a duplicate of something from the computed data project, right? renderData was fixed for 0.11.0 but is deprecated in favor of the new eleventyComputed
feature. Please use that instead.
For anyone running into this issue, I noticed that setting the title
directly to {{ tag }}
results in {"object Object":null}
being injected into the content. The fix is to add single quotes around the tag, like this:
eleventyComputed:
title: '{{ tag }}'
The below will not work:
eleventyComputed:
title: {{ tag }}
My feeling is this is a yaml parsing issue where this is not picked up as a string. 😕
Describe the bug I am using 11ty for my static blog site and trying to set up tag pages. Everything else seems to work except the page title
Layout
tags.html
Also have tried
In both cases, my title is set to
[object Object]
, after adding one filter I console log the data and got{ '[object Object]': null }
Am I doing anything wrong here?