Add attribute in Sightly/HTL only if it exists (AEM)

3.4k Views Asked by At

I have a component that takes the path of an image from the dialog and renders it. Here's the snippet of the component -

<div class="${something}" style="background-image:url('${properties.backgroundImageReference @ context='styleString'}');">
</div>

This works fine but I would like to add a logic to generate the style attribute only if properties.backgroundImageReference exists.

Is there a quick way of doing this? Please note that I do not want to use an enclosing data-sly-test condition.

Thanks

2

There are 2 best solutions below

2
On BEST ANSWER

You could have the whole style string generated in an Use-Object that could return null/empty when the property is not set, then the attribute will be skipped.

See https://github.com/adobe/aem-core-wcm-components/blob/master/content/src/content/jcr_root/apps/core/wcm/components/container/v1/container/simple.html#L21 for an example!

Another option would be to define the whole background style with data-sly-set and leverage the ternary operator:

<div class="${something}" 
   data-sly-set.backgroundStyle="background-image:url('${properties.backgroundImageReference @ context='styleString'}');"
   style="${properties.backgroundImageReference ? backgroundStyle : ''}">
</div>
0
On

Here all three options of approaching this

Sling Model

Using sling models is the preferred way because it provides a better separation of concerns and keeps your HTL clean and you can write tests for your model.

package com.yourproject.models;

@Model(adaptables = Resource.class ,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class Image {

   @ValueMapValue
   private String backgroundImageReference;

   private String backgroundStyle;

   @PostConstruct
   public void init() {
       if (backgroundImageReference != null) {
         backgroundStyle = String.format("background-image:url('%s')", backgroundImageReference);
      }
   }

   public String getBackgroundStyle() {
      return backgroundStyle;
   }
}
<sly data-sly-use.image="com.yourproject.models.Image">
    <div class="${something}" style="${image.backgroundStyle}">
    </div>
</sly>

HTL Only

You can opt for a HTL-only approach in case you feel a Sling Model is overkill. Downside is your HTL will turn complex and hard to maintain very quickly.

<sly data-sly-test.backgroundImage="background-image:url('${properties.backgroundImageReference});"
            data-sly-test.backgroundImageStyle="${properties.backgroundImageReference ? backgroundImage : '' }"></sly>

<div class="${something}" style="${backgroundImageStyle}"></div>

Use.js

Use.js is the least recommended way in my opinion. You can't debug the code, you can't write tests, uses a very old JS engine to compile JS into Java and has some very nasty bugs, like boolean comparison

// image.use.js    

'use strict';
use([], function () {
    var backgroundImageReference = properties.get('backgroundImageReference', '');
    var backgroundStyle = backgroundImageReference != ''
        ? "background-image:url('" +  backgroundImageReference + "')"
        : '';

    return {
        backgroundStyle: backgroundStyle
    };
});
<sly data-sly-use.image="image.use.js">
    <div class="${something}" style="${image.backgroundStyle}">
    </div>
</sly>