AMP: mustache template loop variable in amp-list? - html

I'm using amp-list together with amp-mustache templates to display a list of blog articles on my AMP page, like this example:
<amp-list
width="auto"
height="100"
layout="fixed-height"
src="/data/blog-list.json"
>
<template type="amp-mustache">
<div class="blogitem blogitem--horizontal">
{{title}}
...
</div>
</template>
</amp-list>
However, I need the first item in my list to appear different than the others. I have slightly different html for the first item. Is there some kind of loop variable available that I can use to do something like this:
<amp-list
width="auto"
height="100"
layout="fixed-height"
src="/data/blog-list.json"
>
<template type="amp-mustache">
{{#if loop->first}}
<div class="blogitem blogitem--vertical">
{{title}}
...
</div>
{{#else}}
<div class="blogitem blogitem--horizontal">
{{title}}
...
</div>
{{/if}}
</template>
</amp-list>
Or is there another way to accomplish this?
Thanks!

Related

<amp-carousel> not working as expected with dynamic data using <amp-list>

I have my HTML:
<amp-list height="400" layout="fixed-height" src="data.json">
<template type="amp-mustache">
<amp-carousel height="200" layout="fixed-height" type="carousel">
<amp-img src="img/{{ imgSrc }}.jpg" layout="fixed" width="100" height="100" alt="{{ productName }}"></amp-img>
</amp-carousel>
</template>
</amp-list>
Which should display a carousel with the product images I've specified within the data.json file. However, if you take a look at my page here, it isn't functioning as I'd expect. I tried removing the dynamic functions and it works as expected, so something with the <amp-list> is confusing it. I followed the issues on the AMP Project GitHub: here, here, and here.
Here's what the component should look like:
https://ampbyexample.com/playground/#url=https%3A%2F%2Fampbyexample.com%2Fcomponents%2Famp-carousel%2Fsource%2F&mode=Responsive
And here's what it looks like currently:
https://www.perfectimprints.com/amp/product/offering-buckets/
Any insights would be much appreciated. Thanks!
They key is to use the amp-list in single-item mode and then manually iterate over the different items:
<amp-list width="325" height="325" layout="fixed" single-item src="/items.json">
<template type="amp-mustache">
<amp-carousel type="slides" layout="fill">
{{#items}}
<amp-img src="{{src}}" layout="fill" alt="{{alt}}"></amp-img>
{{/items}}
</amp-carousel>
</template>
</amp-list>
Another trick is to let the amp-list define the layout and then use the fill layout for carousel and images.
I got some solution for it.
{
items: [
{
values: [
{
category:"cate1",
image_link: "url1",
},
{
category:"cate1",
image_link: "url2",
},
{
category:"cate1",
image_link: "url3",
},
{
category:"cate1",
image_link: "url4",
},
]
}
]
}
above json data format we are getting from api.
if you does not has this format data from api then you have to chage to this format only.
<amp-list id="list_id" width="350" height="150" layout="flex-item"
src="api url">
<template type="amp-mustache">
<amp-carousel width="350" height="150" layout="fixed" type="carousel" autoplay delay="2000"
loop>
{{#values}}
<div role="text">
<amp-img src="{{image_link}}" layout="fixed" width="100" height="100" alt="{{title}}">
</amp-img>
<p class="category_label">{{category}}</p>
</div>
{{/values}}
</amp-carousel>
</template>
</amp-list>
above code for carousel.
it will display like above.
Thanks
Vishal
There is a workaround which you need to try.
amp-list expects an items array or object. For amp-carousel to work with amp-list and amp-mustache, you need to structure your response like this.
{"items": [{
"values": [/*...*/]
In your html code do this,
<amp-list height="400" layout="fixed-height" src="data.json">
<template type="amp-mustache">
<amp-carousel height="400" layout="fixed-height" type="carousel">
{{#values}}
<amp-img src="img/{{imgSrc}}.jpg" layout="fixed" width="100" height="100" alt="{{productName}}"></amp-img>
{{/values}}
</amp-carousel>
</template>
</amp-list>
If your arrows are disappearing, then you need to add controls attribute to amp-carousal.
<amp-carousel height="400" layout="fixed-height" type="carousel" controls>
.
.
</amp-carousel>

amp-list not printing returned data from the connected JSON file

I'm trying to implement amp-list to allow a different currency depending on where the user is from. I've implemented the amp-list element and created a JSON file (which is a CORS url), containing the data using the correct syntax.
The amp-list however is not printing the data, and instead printing a blank space. The HTML template is:
<amp-list width="auto"
height="50"
layout="fixed-height"
src="/amp-price/57938">
<template type="amp-mustache">
<p class="price align-center {{test}}">{{price}}</p>
</template>
</amp-list>
And the JSON response is:
{"items": [{"price": "\u00a321.59", "test": "test"}]}
But the rendered HTML is:
<amp-list width="auto" height="50" layout="fixed-height" src="/amp-price/57938" class="i-amphtml-element i-amphtml-layout-fixed-height i-amphtml-layout-size-defined i-amphtml-layout" aria-live="polite" style="height: 50px;">
<template type="amp-mustache">
<p class="price"> - </p>
</template>
<div class="i-amphtml-fill-content i-amphtml-replaced-content" role="list"></div></amp-list>
The JSON response has all the correct AMP headers, and I'm not getting any AMP errors in the console.
I've also followed the src link in the page source and it goes to the correct URL.
Is there something simple I'm missing?
I had the same problem and I tried almost everything. The amp-list in safari 10 doesn't load the json endpoint.
But the solution for me is to add credentials="include" into my amp-list tag:
the final amp-list:
<amp-list credentials="include" id="smallcartsList" width="auto" height="#HeightRequest" [height]="CurrentCartList.items.length == 0 ? 5 : 50 * CurrentCartList.items.length" media="(max-width: 1199px)" layout="fixed-height" binding="no" src="/API/CartList/GetCartsList" [src]="cartlistsource" template="cartlistdetail"> </amp-list>
Sebastian Benz is correct I have use the same code and working fine
Here is working url
HEAD JS
<script async custom-element="amp-list" src="https://cdn.ampproject.org/v0/amp-list-0.1.js"></script>
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.1.js"></script>
BODY HTML
<amp-list width="auto"
height="50"
layout="fixed-height"
src="https://jsonblob.com/api/jsonBlob/1f6f838d-25aa-11e8-8863-d99090d9ec78">
<template type="amp-mustache">
<p class="price align-center {{test}}">{{price}}</p>
</template>
</amp-list>
JSON DATA LINK

Update amp-list data source without form

I have an amp-list and I want to update its src dynamically without using form, just using a bunch of button divs that use data from amp-state that changes on tap on an element.
For example, tapping #elementOne will change product.currentIndex to 1, so list's [src] will change to 'localhost/example/data?page=' + product.currentIndex = 'localhost/example/data?page=1', hence the amp-list will be updated after src change.
Here's what I've tried so far:
<amp-state id="product">
<script type="application/json">
{
"page": 0
}
</script>
</amp-state>
<amp-state id="productState"
[src]="'localhost/example/data?page=' + product.page"
src="localhost/example/data?page=0"></amp-state>
<div role="button" tabindex="0" on="tap:AMP.setState({product: {page: 1 }})">
<span>Page One</span>
</div>
<div role="button" tabindex="0" on="tap:AMP.setState({product: {page: 2 }})">
<span>Page Two</span>
</div>
<amp-list width="auto" height="1024" layout="fixed-height"
src="localhost/example/data" [src]="productState.items">
<template id="product-item-template">
<!-- A template -->
</template>
</amp-list>
Is there a way to do this without using form?
Just simply bind the src attribute of the amp-list to the calculated url string, like this:
[src]="'/example/data/?page=' + product.page"
Your markup should look like this:
<amp-list width="auto" height="1024" layout="fixed-height"
src="localhost/example/data" [src]="'/example/data/?page=' + product.page">
<template id="product-item-template">
<!-- A template -->
</template></amp-list>

How can I repeat a piece of HTML multiple times without ngFor and without another #Component?

I want to repeat a piece of HTML, multiple times in my template.
But I want it to be repeated at different places on my page. This means that ngFor is not the solution as the pieces would be repeated directly one after the other.
A 'working solution' would be to define a specific #Component for my repeated HTML, and do something like that :
<p>Whatever html</p>
<my-repeated-html></my-repeated-html>
<h4>Whatever</h4>
<my-repeated-html></my-repeated-html>
But I find it overkill to create a dedicated component for doing something like that, it has no functional meaning and is only required by the HTML structure I want to set up.
Is there really nothing in ng2 template engine to allow me to define an "inner template" and use it wherever I need it in the current template?
update Angular 5
ngOutletContext was renamed to ngTemplateOutletContext
See also https://github.com/angular/angular/blob/master/CHANGELOG.md#500-beta5-2017-08-29
original
The recently added ngTemplateOutlet might be what you want
<template [ngTemplateOutlet]="templateRefExpression" [ngOutletContext]="objectExpression"></template>
It can currently be used like
<template #templateRef>
<pre>{{self | json }}</pre>
</template>
<template [ngTemplateOutlet]="templateRef"></template>
A template can also be passed to a child component to be rendered there
#Component({
selector: 'some-child',
providers: [],
template: `
<div>
<h2>Child</h2>
<template [ngTemplateOutlet]="template" ></template>
<template [ngTemplateOutlet]="template" ></template>
</div>
`,
directives: []
})
export class Child {
#ContentChild(TemplateRef) template:TemplateRef;
}
to be used like
<some-child>
<template>
<pre>{{self | json }}</pre>
</template>
</some-child>
stackblitz example
Another Plunker example
that uses data passed as
<template [ngTemplateOutlet]="..." [ngOutletContext]="templateData"
This way ngOutletContext can be used in the template like
<template let-image="image">
{{image}}
where image is a property of templateData
If $implicit is used
<template [ngTemplateOutlet]="..." [ngOutletContext]="{$implicit: templateData}"
the ngOutletContext can be used in the template like
<template let-item>
{{item}}
<campaign-channels-list (onItemSelected)="_onItemSelected($event)" [customTemplate]="customTemplate" (onDragComplete)="_onDragComplete($event)" [items]="m_blockList"></campaign-channels-list>
<template #customTemplate let-item>
<a href="#" [attr.data-block_id]="item.blockID">
<i class="fa {{item.blockFontAwesome}}"></i>
<span>{{item.blockName}}</span>
<i class="dragch fa fa-arrows-v"></i>
<span class="lengthTimer hidden-xs">
{{item.length | FormatSecondsPipe}}
</span>
</a>
</template>
and in rx component:
<div class="sortableList">
<li (click)="_onItemSelected(item, $event, i)" *ngFor="let item of m_items; let i = index" class="listItems list-group-item" [ngClass]="{'selectedItem': m_selectedIdx == i}">
<template [ngTemplateOutlet]="customTemplate" [ngOutletContext]="{$implicit: item}">
</template>
</li>
</div>
pay attention to:
[ngOutletContext]="{$implicit: item}"
as well as
<template #customTemplate let-item>

Polymer bind value through core element

I have a problem with passing the category variable inside the <template> tag wrapped by the core-list.
I tried different binding approaches, but no luck. {{category}} corretcly appears outside the 2nd template tag.
<polymer-element name="library-list" attributes="category">
<template>
<style>
...
</style>
<service-library id="library" items="{{items}}"></service-library>
<core-list id="list" data="{{items}}" on-core-select="{{onClick}}">
<template>
<div class="item {{ {selected: selected} | tokenList }}" hidden?="{{category == type}}">
<div class="message">
<span class="title">{{title}}</span>
</div>
</div>
</template>
</core-list>
</template>
Maybe you want to try the injection approach.
<core-list data="{{data}}">
<template>
<div class="item {{ {selected: selected} | tokenList }}">
<span>{{foo}}-<b>{{category}}</b></span>
</div>
</template>
</core-list>
...
data.push({
foo: 999,
category:this.category,
...});
jsbin demo http://jsbin.com/mokok
I couldn't find a good solution, so I filtered the data instead that the core-list displays.