Search code examples
aemsightly

Is it possible in HTL/Sightly to open or close tag conditionally?


I'm new to AEM, so any advice is appreciated.

Let's say I've something like this:

<div class="big-item" data-sly-list="${features.list}">
     
     <sly data-sly-test="${ itemList.first || itemList.count == 5 || itemList.count == 9 || itemList.count == 13 || itemList.count == 17 }">
         <div class="small-item-wrapper>
             <div class="additional-div">
     </sly>

            <div class="small-item">
                <div>${item.somecontent}</div>
            </div>

     <sly data-sly-test="${ itemList.last || itemList.count == "4 || itemList.count == 8 || itemList.count == 12 || itemList.count == 16 }">               
            </div>   
            </div>  
      </sly>

</div>

Basically, what I'm trying to do is to wrap every 4 items in a separate container.

For now, the closing tag isn't rendered or rather is closed only after the last iteration.

Is such an html-templating approach doable in AEM? Can I do this purely in htl? Currently, this does not work for me, I suppose there's some automation going on which I'm not aware of.

How can I do this?

PS. When the structure is simple (no nested divs) seems to be working, when subdivs are added it starts to break.


Solution

  • No, that's not allowed as the HTL script should be a valid HTML (hence no unfinished/conditional tags). There are a few workaround though. Let's assume your items look like (JS use-object that can be tested with HTL REPL):

    use(function () {
        return {
            list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        };
    });
    

    You could then render them with this HTL script:

    <div class="big-item" data-sly-use.logic="logic.js">
        <div class="small-item-wrapper" data-sly-test="${logic.list.length > 0}">
            <div class="additional-div">
                <div class="small-item" data-sly-repeat="${logic.list @ begin=0, end=3}">
                    <div>${item}</div>
                </div>
            </div>
        </div>
         <div class="small-item-wrapper" data-sly-test="${logic.list.length > 4}">
            <div class="additional-div">
                <div class="small-item" data-sly-repeat="${logic.list @ begin=4, end=7}">
                    <div>${item}</div>
                </div>
            </div>
        </div>
         <div class="small-item-wrapper" data-sly-test="${logic.list.length > 8}">
            <div class="additional-div">
                <div class="small-item" data-sly-repeat="${logic.list @ begin=8, end=11}">
                    <div>${item}</div>
                </div>
            </div>
        </div>
         <div class="small-item-wrapper" data-sly-test="${logic.list.length > 12}">
            <div class="additional-div">
                <div class="small-item" data-sly-repeat="${logic.list @ begin=12, end=15}">
                    <div>${item}</div>
                </div>
            </div>
        </div>
    </div>
    

    It's ugly and hardcoded up to 16 items but should work.

    If you can "massage" the data ahead of time you could prepare a set of [begin, end] markers and make the HTL script nicer. Here's the use-object:

    use(function () {
        let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
        let markers = [];
        for (let i=0; i<list.length; i++) {
            if (i % 4 === 0) {
                markers.push([i, i+3]);
            }
        }
        return {
            markers: markers,
            list: list
        };
    });
    

    and corresponding HTL script:

    <div class="big-item">
        <div class="small-item-wrapper" data-sly-repeat.marker="${logic.markers}">
            <div class="additional-div">
                <div class="small-item" data-sly-repeat="${logic.list @ begin=marker[0], end=marker[1]}">
                    <div>${item}</div>
                </div>
            </div>
        </div>
    </div>