Работа с удаленными данными
Ваши привязываемые данные слишком велики или сложны для извлечения при загрузке страницы? У каждого варианта товара есть цена, на поиск которой уходит много времени? Поиск цен для разных вариантов непросмотренных товаров — пустая трата времени.
<amp-state> поддерживает загрузку удаленных данных через атрибут src, который загружает JSON из конечной точки CORS. Эта загрузка выполняется один раз при загрузке страницы и полезна для обеспечения актуальности данных (особенно при загрузке из кеша).
Вы также можете привязать атрибут src к элементу <amp-state>. Это означает, что действие пользователя может инициировать загрузку удаленных данных JSON в привязываемое состояние страницы.
Загрузка имеющихся размеров рубашки
Давайте воспользуемся возможностью извлечения удаленных данных, чтобы получить цены вариантов товаров, представленных в нашей выборке. Наш сервер разработки Express.js в app.js уже имеет конечную точку /shirts/sizesAndPrices?shirt=<sku> которая, учитывая варианты рубашки, возвращает доступные размеры и цену для каждого размера. Он отправляет ответ с искусственной задержкой в одну секунду для имитации задержки в сети.
| Запрос | Ответ | 
|---|---|
GET /shirts/sizesAndPrices?sku=1001 | 
{"1001: {"sizes": {"XS": 8.99, "S" 9.99}}} | 
Подобно данным JSON внутри элементов <amp-state>, удаленные данные, возвращаемые из этих выборок, объединяются и доступны в атрибуте id элемента. Например, к данным, возвращенным из приведенного выше примера ответа, можно получить доступ в выражении:
| Выражение | Результат | 
|---|---|
shirts['1001'].sizes['XS'] | 
8.99 | 
Привяжите данные
Теперь давайте применим это в нашем примере интернет-магазина. Сначала давайте извлечем данные рубашки при выборе нового варианта. Добавьте привязку [src] к нашему элементу amp-state#shirts :
<!-- When `selected.sku` changes, update the `src` attribute and fetch
     JSON at the new URL. Then, merge that data under `id` ("shirts"). -->
<amp-state
  id="shirts"
  [src]="'/shirts/sizesAndPrices?sku=' + selected.sku"
></amp-state>
Укажите отсутствующие размеры
Далее давайте четко пометим отсутствующие размеры как таковые для данного варианта товара. CSS-класс "unavailable" перечеркивает элемент диагональной линией — мы можем добавить его в соответствующие отсутствующим размерам элементы, размещенные внутри amp-selector:
<amp-selector name="size">
  <table>
    <tr>
      <!-- If 'XS' size is available for selected SKU, return empty string.
           Otherwise, return 'unavailable'. -->
      <td [class]="shirts[selected.sku].sizes['XS'] ? '' : 'unavailable'">
        <div option="XS">XS</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['S'] ? '' : 'unavailable'">
        <div option="S">S</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['M'] ? '' : 'unavailable'">
        <div option="M">M</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['L'] ? '' : 'unavailable'">
        <div option="L">L</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['XL'] ? '' : 'unavailable'">
        <div option="XL">XL</div>
      </td>
    </tr>
  </table>
</amp-selector>
Теперь перезагрузите страницу и попробуйте ее в работе. Выбор нового варианта товара (цвета рубашки) приведет к вычеркиванию отсутствующих размеров (после небольшой задержки).
Укажите начальные состояния
Есть небольшая проблема — что делать с рубашкой черного цвета, т. е. цвета, выбранного по умолчанию? Нам нужно будет добавить данные о размерах и цене черной рубашки в amp-state#shirts, поскольку amp-bind запускается только в ответ на явные действия пользователя:
<amp-state id="shirts" [src]="'/shirts/sizesAndPrices?sku=' + selected.sku">
  <script type="application/json">
    {
      "1001": {
        "color": "black",
        "image": "./shirts/black.jpg",
        "sizes": {
          "XS": 8.99,
          "S": 9.99
        }
      },
<!-- ... -->
Нам также нужно обновить состояние по умолчанию соответствующих элементов:
<amp-selector name="size">
  <table>
    <tr>
      <!-- If 'XS' size is available for selected SKU, return empty string.
           Otherwise, return 'unavailable'. -->
      <td [class]="shirts[selected.sku].sizes['XS'] ? '' : 'unavailable'">
        <div option="XS">XS</div>
      </td>
      <td [class]="shirts[selected.sku].sizes['S'] ? '' : 'unavailable'">
        <div option="S">S</div>
      </td>
      <!-- Add the 'unavailable' class to the next three <td> elements
           to be consistent with the available sizes of the default SKU. -->
      <td
        class="unavailable"
        [class]="shirts[selected.sku].sizes['M'] ? '' : 'unavailable'"
      >
        <div option="M">M</div>
      </td>
      <td
        class="unavailable"
        [class]="shirts[selected.sku].sizes['L'] ? '' : 'unavailable'"
      >
        <div option="L">L</div>
      </td>
      <td
        class="unavailable"
        [class]="shirts[selected.sku].sizes['XL'] ? '' : 'unavailable'"
      >
        <div option="XL">XL</div>
      </td>
    </tr>
  </table>
</amp-selector>
Переменные цены на рубашки
Теперь, когда мы правильно отображаем доступные размеры, давайте удостоверимся, что отображается правильная цена.
Наш магазин AMPPAREL отличается тем, что цена на рубашку зависит от цвета и размера. Это означает, что нам нужна новая переменная для отслеживания выбранного пользователем размера. Добавьте новое действие к нашему элементу размера amp-selector:
<!-- When an element is selected, set the `selectedSize` variable to the
     value of the "option" attribute of the selected element.  -->
<amp-selector
  name="size"
  on="select:AMP.setState({selectedSize: event.targetOption})"
></amp-selector>
Обратите внимание, что мы не инициализируем значение selectedSize через элемент amp-state#selected. Это потому, что мы намеренно не предоставляем выбранный размер по умолчанию и вместо этого хотим заставить пользователя выбирать размер.
AMP.setState() может использоваться для определения новых переменных в дополнение к изменению существующих. Выражения оценят неопределенные переменные в null. Добавьте новый элемент <span> обертывающий ценовую метку, и измените текст по умолчанию на «---», поскольку размер по умолчанию не выбран.
<h6>
  PRICE :
  <!-- Display the price of the selected shirt in the selected size if available.
       Otherwise, display the placeholder text '---'. -->
  <span [text]="shirts[selected.sku].sizes[selectedSize] || '---'">---</span>
</h6>
И у нас правильные цены! Попробуйте это.
Условно-активная кнопка
Мы почти закончили! Давайте отключим кнопку «Добавить в корзину», когда выбранный размер недоступен:
<!-- Disable the "ADD TO CART" button when:
     1. There is no selected size, OR
     2. The available sizes for the selected SKU haven't been fetched yet
-->
<input
  type="submit"
  value="ADD TO CART"
  disabled
  class="mdl-button mdl-button--raised mdl-button--accent"
  [disabled]="!selectedSize || !shirts[selected.sku].sizes[selectedSize]"
/>
Попробуйте в действии: если вы выберете недоступный размер, вы не сможете добавить его в корзину.