Search code examples
javascripthtmlamp-html

How to render same element multiple times in AMP?


Suppose I have the following json about the user reviews:

{
  "reviewRating": 4,
  "comment": "this is great"
}

Then I use amp-list to loop through the reviews.

<amp-list items="." single-item>
  <template type="amp/mustache">
    <!-- How can I render 4 star images here? -->
    <span>Rating: {{reviewRating}}</span>
    <p>{{comment}}</p>
  </template>
</amp-list>

For the reviewRating, I want to render the same number of stars from reviewRating key/value to make a better look and feel. How can I do this in AMP?


Solution

  • This is possible by combining amp-bind and amp-list:

    <amp-bind-macro id="classForRating" arguments="rating, index" expression="rating >= index ? 'star-full' : (rating >= (index - 0.5) ? 'star-half' : 'star-empty')" ></amp-bind-macro>
    <amp-state id="state" src="rating.json"></amp-state>
    <amp-list width="136" height="24" src="rating.json" single-item items="rating" noloading>
      <template type="amp-mustache">
        <div class="star-rating" aria-label="rating: {{.}}" [aria-label]="'rating: ' + state.rating">
          <span [class]="classForRating(state.rating, 1)" class="star-empty"></span>
          <span [class]="classForRating(state.rating, 2)" class="star-empty"></span>
          <span [class]="classForRating(state.rating, 3)" class="star-empty"></span>
          <span [class]="classForRating(state.rating, 4)" class="star-empty"></span>
          <span [class]="classForRating(state.rating, 5)" class="star-empty"></span>
        </div>
      </template>
      <div class="star-rating" placeholder>
        <span class="star-empty"></span>
        <span class="star-empty"></span>
        <span class="star-empty"></span>
        <span class="star-empty"></span>
        <span class="star-empty"></span>
      </div>
    </amp-list>
    

    The trick is to use the same endpoint for amp-state and amp-list. The AMP runtime's response caching ensures that this will only result in a single request. AMP bindings inside an amp-list will be evaluated when the list content is being rendered. This makes it possible to set the star values (via CSS classes) using amp-bind.

    To provide a good loading experience, I've also disabled the amp-list's default loading indicator using the noloading attribute. Instead I'm using a placeholder element showing empty stars while loading.

    Here is a working version.