Amphtml: Nested templates, e.g amp-list inside div <amp-access>

Created on 25 Oct 2016  Â·  14Comments  Â·  Source: ampproject/amphtml

Would it be possible to render an <amp-list> from a src whose URL has a variable substituted by an outer template? For example:

<div amp-access="access AND token">
  <template amp-access-template type="amp-mustache">
    List endpoint: /json/{{token}}.json:<br/>
    <amp-list width=auto height=100 layout=fixed-height src="<%host%>/json/{{token}}.json">
      <template type="amp-mustache" id="amp-template-id">
        <div><a href={{url}}>{{title}}</a></div>
      </template>
    </amp-list>
    You got the token {{token}}!
  </template>
</div>

I've tried this with the amp-access sample by making the authorization endpoint return

{
  "token": "examples",
  "access": true
}

but I get the following error:

Template not found for  <amp-list width=​"auto" height=​"100" layout=​"fixed-height" src=​"http:​/​/​localhost:​8080/​json/​examples.json" class=​"-amp-element -amp-layout-fixed-height -amp-layout-size-defined -amp-layout -amp-error" id=​"AMP_16" style=​"height:​ 100px;​">​…​</amp-list>​
Dd @ error.js:69
log.js:243 Uncaught Error: task failed: amp-list#16#L amp-list#16: Template not found for amp-list#AMP_16​​​ _reported_
    at xa.f.assert (log.js:243)
    at qf (template-impl.js:208)
    at nf.findAndRenderTemplateArray (template-impl.js:189)
    at amp-list.js:67

image

Feature Request

Most helpful comment

Unfortunately, nested templates is blocked on an AMP validation issue. See workarounds here: https://github.com/ampproject/amphtml/blob/master/extensions/amp-mustache/amp-mustache.md#nested-templates

All 14 comments

/to @dvoytenko

@dandv The reason for this is because currently AMP disallows nested <template> tags. I can look if I can change that, though it'd require an additional security review. That being said, I believe you can achieve something similar with this code:

<div amp-access="access AND token">
    <amp-list width=auto height=100 layout=fixed-height
              src="<%host%>/json/AUTHDATA(token).json">
      <template type="amp-mustache" id="amp-template-id">
        <div><a href={{url}}>{{title}}</a></div>
      </template>
    </amp-list>
</div>

@dandv — have you tried @dvoytenko's suggestion? Is the original request still needed?

From today's discussion:

Supporting nested templates would support a wider range of use-cases that we need to support soon anyway (other components like date-picker in amp-list. or even nested amp-list).

@aghassemi Would love to have this more fleshed out -- specifically use cases where "reference-template-by-id" is insufficient or awkward to use. /cc @ericlindley-g

@danielrozenberg also brought up the fact that we should clearly define what expected behavior is for this case.

<template>
  {{a}} {{b}}
  <template>
    {{b}} {{c}}
  </template>
</template>

We also discussed a possible infinite loop edge case of a self-rendering amp-list that should be addressed.

Regarding supporting nested templates:
This is something that is allowed in HTML and the way it works is that activating the outer template does not activate the inner ones. https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-gotcha

This behaviour seems compatible what we would want in AMP as well. When a parent template is rendered, the inner template is untouched and left to however needs to activate it later.

So in the case of

<div amp-access="access AND token">
  <template amp-access-template type="amp-mustache">
    List endpoint: /json/{{token}}.json:<br/>
    <amp-list width=auto height=100 layout=fixed-height src="<%host%>/json/{{token}}.json">
      <template type="amp-mustache" id="amp-template-id">
        <div><a href={{url}}>{{title}}</a></div>
      </template>
    </amp-list>
    You got the token {{token}}!
  </template>
</div>

when amp-access renders the outer template, we end up with:

<div amp-access="access AND token">
    List endpoint: /json/1234.json:<br/>
    <amp-list width=auto height=100 layout=fixed-height src="<%host%>/json/1234.json">
      <template type="amp-mustache" id="amp-template-id">
        <div><a href={{url}}>{{title}}</a></div>
      </template>
    </amp-list>
    You got the token 1234!
</div>

Note that {{token}} is NOT available in the inner template.

Now from the perspective of amp-list it has no idea it used to be in a template and when it looks for its template to render it will see

      <template type="amp-mustache" id="amp-template-id">
        <div><a href={{url}}>{{title}}</a></div>
      </template>

and when it renders we end up with something like:

<div amp-access="access AND token">
    List endpoint: /json/1234.json:<br/>
    <amp-list width=auto height=100 layout=fixed-height src="<%host%>/json/1234.json">
      <div><a href=foo1.com>foo1</a></div>
      <div><a href=bar.com>bar</a></div>
    </amp-list>
    You got the token 1234!
</div>

@dvoytenko, do you remember what the security concerns were around supporting nested templates?
@choumx / @danielrozenberg, could you provide an example where we can end up in an infinite-loop?

Example of infinite loop:

<amp-list src="/json">
  <template>{{ markup }}</template>
</amp-list>

Then if /json returns

[
  {"markup": "<amp-list src='/json'><template>{{ markup }}</template></amp-list>"}
]

Then the <amp-list> will expand to print the markup, which would be parsed as an <amp-list> that would retrieve /json and render its inner template the same way as its parent, and so on and so forth. That's a very deliberate shoot-self-in-the-leg scenario tho

as @choumx also pointed out offline, there is no reason we can't do both (e.g support nested templates and "reference-template-by-id" eventually).

My opinion is that although both approaches can handle the same use-cases, the main difference is that in the "reference-template-by-id" approach, every templateable component needs to expose a way to reference a template id as part of its own format whereas nested-templates will just work and is future-proof.

For instance, only amp-list currently supports referencing another template via id (with the template attribute). amp-form doesn't and neither does amp-datepicker.

Both amp-form and amp-datepicker can have multiple templates for different states (e.g. success, failure in case of form. date picker can have unlimited number of templates for different days - such as tuesdays, Jan 5th , etc..).

To make "reference-template-by-id" work, both amp-form and amp-datepicker need to change their format:

There are various options discussed for amp-form in https://github.com/ampproject/amphtml/issues/7118 such as <form success-template=id> or <div submit-success template=id>

For date-picker, we haven't discussed a format that can support referencing templates by Id yet. One approach could be allowing every <template> to be a <div template=id> and handle the nuances (e.g. display:none the divs so they don't create a new line in the middle of the component, update validation rules, etc..)

@danielrozenberg, regarding infinite loop. I haven't tested but based on the code we only allow a very limited 'formatting' (e.g. <b>, <i> etc..) markup for unescaped values. So if a {{var}} has any markup other than simple tags, they get escaped (or maybe removed, not sure). Therefore {"markup": "<amp-list src='/json'><template>{{ markup }}</template></amp-list>"} is not supported.

@aghassemi I believe the only security concern for nesting templates was avoidance of recursion. Probably easy enough to control for, but must be thoroughly unit-tested.

I got this error in amp version: 1903141753530

The tag 'template' may not appear as a descendant of tag 'template'. AMP_HTML_TEMPLATE_PROBLEM
line 46, column 101064

The tag 'template' may not appear as a descendant of tag 'template'. AMP_HTML_TEMPLATE_PROBLEM
line 46, column 102721

amp-access -> amp-access-template -> amp-list -> template

this should work?

Unfortunately, nested templates is blocked on an AMP validation issue. See workarounds here: https://github.com/ampproject/amphtml/blob/master/extensions/amp-mustache/amp-mustache.md#nested-templates

thanks @choumx

Is there a similar functionality to amp-access-template for amp-subscriptions? I want to use the response from authorizationUrl but I cannot get mustache to do it.

/to @jpettitt @chenshay

Was this page helpful?
0 / 5 - 0 ratings