Expand my Community achievements bar.

Enhance your AEM Assets & Boost Your Development: [AEM Gems | June 19, 2024] Improving the Developer Experience with New APIs and Events
SOLVED

Recommended approach to pass parameter's to data-sly-template from data-sly-use

Avatar

Level 8

We are working on developing reusable html snippets in form of small html templates so we can include or call the same from multiple components. Here we have to pass multiple parameters through the hierarchy to different templates . However for maintainability purpose we were thinking of using sling models here. But as per our current scope we really don't have any server side operation which needs java/sling models.

So is the really recommended to use slingmodels here to get the parameters structured or any other method to achieve the same considering all the maintainability aspects

 

eg: 

<sly data-sly-call="${temp.comp1 @ 
param1='p1',
param2='p2',
param3='p3',
param4='p4'}" />
</sly>
<template data-sly-template.comp="${@ param1, param2, param3, param4 }">

 

1 Accepted Solution

Avatar

Correct answer by
Level 4

Hi @sherinregi ,

 

You are right, it's better to always use Sling models instead of direct page or component properties. When your project will develop further, you will be able to re-use those models to provide the same data from your component to some single-page app or mobile application (you will just add the Sling Models @Exporter annotation and that's it). Also, you will be able to fulfill your data from other services, even third-party, when the need arises, without rewriting everything. It's something like SOLID approach. Another one is when you need to pass, for example, another version of a model to the same template, like Link, Button, IconButton - the template will use only fields (getters) that exist in the model, so you can leverage data-sly-test to hide elements that don't reflect the model.

Depending on how your FE guys write the code, it is easier to create templates that use models or create templates with a list of parameters. Sometimes it's very hard to push them to re-use their models and/or call the same-purpose parameters with the same names, like they may have URL, link, href, etc, so you will be forced to deal somehow with this, especially on legacy projects. There is no problem if you write both FE and BE or FE guys write directly HTL code.

 

Sometimes I do like that - create several different templates in the same file, one with list of attributes and one or several with models (when FE guys created a mess in their classes). Here is an imaginary example:

<!--/* HTL Template with CTA model parameter */-->
<template
    data-sly-template.ctaUsingModel="${@
       model='Implementation of the CTA model (com.acme.api.Cta)',
       props='List of additional attributes to be added to the CTA (optional)',
       dataLayer='Override analytics properties (optional)'
    }"
>
  <sly data-sly-call="${cta @ assetPath=model.assetPath, props=props,
         link=model.link, id=model.id,
         dataLayer=(dataLayer || model.data)}"></sly>
</template>

<!--/* Template with a list of properties */-->
<template
    data-sly-template.cta="${@
       link='Link model impl (com.adobe.cq.wcm.core.components.commons.link.Link) (optional)',
       id='Id of the button element (optional)',
       text='Text on the CTA',
       props='List of additional attributes to be added to the CTA',
       dataLayer='Analytics properties',
       style='Additional CSS classes for the button'
       .....
     }"


    data-sly-use.iconTpl="/path/to/template.html"
    data-sly-use.anotherTpl="/path/to/another/template.html"
    data-sly-use.someOtherModel="com.acme.models.SomeModel"

    data-sly-set.isAssetButton="${assetPath && true}"
    data-sly-set.isIconButton="${!isAssetButton && icon && true}"
>

  <button
      class="cmp-cta ${style || ''}"
      data-sly-attribute.type="${link.valid ? false : 'button'}"
      data-sly-element="${link.valid ? 'a' : 'button'}"
      aria-label="${accessibilityLabel}"
      data-sly-attribute.id="${id}"
      data-sly-attribute="${link.htmlAttributes}"
      ...>

    <sly data-sly-test="${isAssetButton}"
         data-sly-use.asset="${'com.acme.api.AssetModel' @ path=assetPath}"
         data-sly-call="${anotherTpl.renderMedia @ model=asset, type='button',
           forButtonStyle=style}"></sly>

    <sly data-sly-call="${iconTpl.icon @ icon=button.icon}"
         data-sly-test="${isIconButton}"></sly>

    <span class="cmp-btn__text" data-sly-test="${text}">${text}</span>

  </button>

  <!--/* Display configuration errors to authors */-->
  <sly data-sly-test="${wcmmode.edit}"
       data-sly-test.errors="${asset.errors @ join=','}"
       data-sly-use.configErrorTpl="/authoringErrors.html"
       data-sly-call="${configErrorTpl.error @ error=errors}"></sly>

</template>

Also, if you need to create some wrapper, you can use a template with a parameter for data-sly-call, so you will be able to pass another template to it. However, it's harder to support.

View solution in original post

2 Replies

Avatar

Correct answer by
Level 4

Hi @sherinregi ,

 

You are right, it's better to always use Sling models instead of direct page or component properties. When your project will develop further, you will be able to re-use those models to provide the same data from your component to some single-page app or mobile application (you will just add the Sling Models @Exporter annotation and that's it). Also, you will be able to fulfill your data from other services, even third-party, when the need arises, without rewriting everything. It's something like SOLID approach. Another one is when you need to pass, for example, another version of a model to the same template, like Link, Button, IconButton - the template will use only fields (getters) that exist in the model, so you can leverage data-sly-test to hide elements that don't reflect the model.

Depending on how your FE guys write the code, it is easier to create templates that use models or create templates with a list of parameters. Sometimes it's very hard to push them to re-use their models and/or call the same-purpose parameters with the same names, like they may have URL, link, href, etc, so you will be forced to deal somehow with this, especially on legacy projects. There is no problem if you write both FE and BE or FE guys write directly HTL code.

 

Sometimes I do like that - create several different templates in the same file, one with list of attributes and one or several with models (when FE guys created a mess in their classes). Here is an imaginary example:

<!--/* HTL Template with CTA model parameter */-->
<template
    data-sly-template.ctaUsingModel="${@
       model='Implementation of the CTA model (com.acme.api.Cta)',
       props='List of additional attributes to be added to the CTA (optional)',
       dataLayer='Override analytics properties (optional)'
    }"
>
  <sly data-sly-call="${cta @ assetPath=model.assetPath, props=props,
         link=model.link, id=model.id,
         dataLayer=(dataLayer || model.data)}"></sly>
</template>

<!--/* Template with a list of properties */-->
<template
    data-sly-template.cta="${@
       link='Link model impl (com.adobe.cq.wcm.core.components.commons.link.Link) (optional)',
       id='Id of the button element (optional)',
       text='Text on the CTA',
       props='List of additional attributes to be added to the CTA',
       dataLayer='Analytics properties',
       style='Additional CSS classes for the button'
       .....
     }"


    data-sly-use.iconTpl="/path/to/template.html"
    data-sly-use.anotherTpl="/path/to/another/template.html"
    data-sly-use.someOtherModel="com.acme.models.SomeModel"

    data-sly-set.isAssetButton="${assetPath && true}"
    data-sly-set.isIconButton="${!isAssetButton && icon && true}"
>

  <button
      class="cmp-cta ${style || ''}"
      data-sly-attribute.type="${link.valid ? false : 'button'}"
      data-sly-element="${link.valid ? 'a' : 'button'}"
      aria-label="${accessibilityLabel}"
      data-sly-attribute.id="${id}"
      data-sly-attribute="${link.htmlAttributes}"
      ...>

    <sly data-sly-test="${isAssetButton}"
         data-sly-use.asset="${'com.acme.api.AssetModel' @ path=assetPath}"
         data-sly-call="${anotherTpl.renderMedia @ model=asset, type='button',
           forButtonStyle=style}"></sly>

    <sly data-sly-call="${iconTpl.icon @ icon=button.icon}"
         data-sly-test="${isIconButton}"></sly>

    <span class="cmp-btn__text" data-sly-test="${text}">${text}</span>

  </button>

  <!--/* Display configuration errors to authors */-->
  <sly data-sly-test="${wcmmode.edit}"
       data-sly-test.errors="${asset.errors @ join=','}"
       data-sly-use.configErrorTpl="/authoringErrors.html"
       data-sly-call="${configErrorTpl.error @ error=errors}"></sly>

</template>

Also, if you need to create some wrapper, you can use a template with a parameter for data-sly-call, so you will be able to pass another template to it. However, it's harder to support.

Avatar

Level 8

Thanks for the recommendation. As you said considering the future scope it makes sense to follow the model pattern here