Navigation icons load in layout.html, but not in fragment for apostrophe-headless api - headless

I've created a fragment for apostrophe-headless, which loads my main navigation menu.
'apostrophe-pages': {
restApi: true,
apiTemplates: [ 'leftMenu']
},
This fragment has two functions:
in views/layout.html I {% include "apostrophe-pages:api/leftMenu.html" %} it
and I also pass it onto our angular app through /api/v1/apostrophe-pages/?render=leftMenu.html
in that fragment, I build my menu, including a few navicons.
{%- for tab in homeData._children -%}
{% set imageURL = apos.attachments.url(apos.images.first(tab.navicon), { size: 'one-third' }) or null %}
{{ apos.log(tab.navicon) }}
<li><img src="{{ imageURL }}"></li>
{% endfor %}
PROBLEM: These tab.navicons are not being loaded when this fragment is called through the API.
views/layout.html console.log of tab.navicon
_docId:"cjiqwpbjb00202zya1uf6wcm8"
_dotPath:"navicon"
_edit:true
items:Array(1) [Object]
type:"area"
__proto__:Object {constructor: , __defineGetter__: ,
__defineSetter__: , …}
/api/v1/apostrophe-pages/?render=leftMenu.html console.log of tab.navicon
items:Array(1) [Object]
type:"area"
__proto__:Object {constructor: , __defineGetter__: ,
__defineSetter__: , …}
Any thoughts?
Could it be a filters/depth issue?

Currently this is not possible with apostrophe-headless in a single call. Both the root GET route that fetches the entire tree and the per-page GET route currently have areas(false) hardcoded for performance when loading children.
This could be remedied by adding an initially empty method that is given a chance to modify that cursor object before the query takes place. Then project-level overrides would be possible. That would require a pull request to apostrophe-headless but it wouldn't be a very difficult one.
In the meantime, the workaround is to make additional apostrophe-headless calls for each of the child pages. The response for the page itself will always load areas (and thus join with images, populating the data you are looking for). For performance you could cache these responses in your client code.
I have opened a github issue on this.

Related

Rendering a component inside another in Nunjucks & Fractal

I'm working on a design system and just getting my head around the component way of thinking.
We're using Nunjucks and Fractal.
We have an existing component, an accordion which gets it's data from a JSON object. The props being title and content.
I've built a component, like a table of contents, which displays a list of styled links, using a simple loop, pulling in from a ToC.config.js file.
I need to include that new component within the accordion component, the ToC has a title and an array containing urls and text for each link.
At present I've just copied the HTML from the accordion's view in Fractal, but that's probably not the way to go, but visually it's as the designer requires.
I can also render the accordion correctly if I put all the links, HTML and all in the config, as a string, but that's not the way it should work either.
What I want to do, which is probably the proper way, is pull that accordion in and populate it with my ToC component.
{% render '#my-accordion', 'accordion: items' %} doesn't do what I want and I can't seem to figure out how to achieve what I need to do.
Something like so:
{% render '#my-accordion' %}
// Pass in data from ToC, somehow
{{ title: title }}
{% for item in items %}
{{ item.text etc }}
{% endfor %}
Then I would have my accordion component, where its title, links and HTML etc are those from my ToC component. Sorry for the rough pseudo above, it's more an example of what I want to do. I can't copy code to an external resource.
using render doesn't appear to be the way to go, unless I'm missing something? I can't pass the list through as a string as it has classes and aria for the current page etc and content authors will be building pages with these.
A little nudge in the right direction would be great.
You can add a render-filter that similar to include and macro.
import 'nunjucks.min.js';
var env = new nunjucks.Environment({autoescape: true});
env.addFilter('render', function (template, ctx) {
const html = env.render(template, ctx); // try-catch
return env.filters.safe(html);
});
Usage
// table.njk
<table>
{% for e in rows %}
{% 'row.njk' | render({row: e}) %}
{% endfor %}
</table>
// row.njk
<tr>
{% for c in row.cols %}
<td> {{ c.name }} </td>
{% endfor %}
</tr>

Navigate through nested yaml list with liquid

I've seen a few questions about this topic but none could solve my problem. I want to have a multilingual jekyll site without using any plugin. I have a yaml file with this nested list
menu:
fr:
home:
name:"Acceuil"
url:"/"
team:
name:"Équipe"
url:"/equipe"
en:
home:
name:"Home"
url:"/home.html"
team:
name:"Team"
url:"/team"
I'd like to print a different menu depending on the page lang option in the yaml front matter. A minimal exemple would be:
---
lang: en
---
<ul>
{% for item in site.menu.[page.lang] %}
<li>{{ item[1].name }}</li>
{% endfor %}
</ul>
and this should print in raw html
Home
Team
But instead my code prints nothing, I just have two bullets with no text. I can't see what I'm doing the wrong way, could you guys help me ?
Edit:
Ok, my only problem was just that I didn't put space between the value indicator and the value. Now the problem is solved. Thanks !
Add a whitespace between colons and values in the menu file, according to the YAML specification:
YAML insists the “:” mapping value indicator be separated from the
value by white space.
Also remove the menu: key and save the menu in a file called _data/menu.yml.
fr:
home:
name: "Acceuil"
url: "/"
team:
name: "Équipe"
url: "/equipe"
en:
home:
name: "Home"
url: "/home.html"
team:
name: "Team"
url: "/team"
Then you can access that data with site.data.menu accessing directly to the lang key without a . between menu and page.lang:
<ul>
{% for item in site.data.menu[page.lang] %}
<li>{{ item[1].name }}</li>
{% endfor %}
</ul>
This generates:
<ul>
<li>Home</li>
<li>Team</li>
</ul>
I've used a similar approach in a multilingual site with nav.yaml and a langnav.html include.

Apostrophe cms - inline editing of rich text in custom widgets?

I can't make inline editing of rich text save back to the db in some cases.
Please bear with me, there will be some code pasted here, as it is the only way I can describe what I'm doing.
I have two kinds of custom widgets in my project - the ones where there is only one instance of the widget, typically defined like this in the lib\modules directory:
article-widgets
- views
- - widget.html
- index.js
And then the kind of widgets that are repeated, and can be used in several places around the site, typically defined like this:
employees
- index.js
employees-widgets
- views
- - widget.html
This one I can make work:
In the first kind I define a rich text are in article-widgets\index.js
{
name: 'ingress',
label: 'Ingress',
type: 'area',
required: true,
options: {
widgets: {
'apostrophe-rich-text': {
toolbar: ['Bold', 'Italic', 'Link', 'Unlink' ]
}
}
}
}
And then in article-widgets\views\widget.html
{{ apos.singleton(data.widget, 'ingress', 'apostrophe-rich-text',{
toolbar: [ 'Bold', 'Italic', 'Link', 'Unlink' ]
}) }}
This one is not working for me:
In the second type - I can edit inline, but changes are not saved.
In employees\index.js
{
name: 'body',
label: 'Beskrivelse',
type: 'area',
options: {
widgets: {
'apostrophe-rich-text': {
toolbar: ['Bold', 'Italic', 'Link', 'Unlink']
}
}
}
}
And then in employees-widgets\views\widget.html
{% for piece in data.widget._pieces %}
<div>
{{
apos.singleton(piece, 'body', 'apostrophe-rich-text', {
toolbar: [ 'Bold', 'Italic', 'Link', 'Unlink' ]
})
}}
</div>
{% endfor %}
I can't understand why the later is not working. Am I doing something wrong - or is inline editing of repeated items not possible?
One of Apostrophe's subtleties is that any property beginning with an underscore (_) (except _id) is not actually part of the parent object and changes don't go back to the database
These are properties attached for convenience by Apostrophe somewhere in the retrieval process.
I don't thinkg modifying the piece from the widget is something baked in by default (typically piece-widgets are single-serving views for content) but it is possible to set up custom backend functionality.
Not a total 1:1 of your issue but if you look at the comments and comments-widgets module in this (rough) example, you can see we're modifying the piece's content via the widget.
https://github.com/stuartromanek/apostrophe-comment-system/tree/master/lib/modules

MailJet-Email Template using conditional statement in BLOCKED ststus

Used mailJet module in node js
// template
Hello {{var:first_name:""}},
Welcome to Mailjet. This is an example of a templating
language message. This message contains variables and
nested loops (for .. endfor)! You could also embed
conditions (if .. else ..).
http://www.mailjet.com"}}">
Here is a link to click!
{% for rock_band in var:rock_bands %}
Title: {{ rock_band.name }}
{% for member in rock_band.members %}
Member name: {{ member }}
{% endfor %}
{% endfor %}
// data
{
"Subject": "test subject",
"MJ-TemplateID": "79501",
"MJ-TemplateLanguage": true,
"Recipients":[{ 'Email':"email here(valid email)"}],
"Vars": {
"first_name": "test name",
"rock_bands" : [{
"name": "test_name",
"members" : ['t','v']
}]
}
};
After successfully send email from node application,i checked MailJet dashboard but it's under BLOCKED status.
but template without conditional statements working fine.
Hope there's solution for it and thanks a ton.
The messages appear with status "blocked" when there is an error in the template. I tested the for loop provided and it worked fine for me so most likely there is another issue in the template syntax. Enable the template error management to receive a report about the error:
https://dev.mailjet.com/guides/#templates-error-management
If you still face troubles finding the error, contact Mailjet support as the issue would be related to the specific template.

Twig : Access to variable from outer scope in a form widget customization

I'm trying to customize a specific widget, like in the documentation : http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field
The problem is that in this custom block, I need to use a variable from my actual template. I thought "blocks have access to variables from outer scopes", but apparently not in this case :
{% extends "CDASvBundle::layout.html.twig" %}
{% block _contact_activity1_widget %}
<select name="contact[activity1]">
{% for key, child_contact_categories in contact_categories_tab %}
<option value="{{key}}">{{child_contact_categories}}</option>
{% endfor %}
</select>
It's saying that contact_categories_tab is undefined, but outside of this block (in the normal content block for example), it works !
I tried something like :
{% use 'form_div_layout.html.twig' with contact_categories_tab as contact_categories_tab %}
But that doesn't either.. Though I'm not sure I understand if I have to use use and how !
I see one other solution that I haven't tried yet : put this customization in another template. But I don't really want to do that (few lines in a new template), there should be a way to do that in only ONE template ?!
Finally found the answer in a previous post :
Each symfony form type extents AbstractType class.
AbstactType class has method:
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->set('img_src', '120x100.jpg');
$view->set('my_variable', $foo);
}
You can create this method on your form type and next in your twig:
{{ asset(img_src) }}
Source : How to get entity or pass variable to Symfony2 twig form widget?

Resources