[SalesForce] Dynamic vertical tab lightning component

I am bout to create an dynamic vertical tabbar which gets its content from a query later on. This turns out to be an issue as the aura:iteration seems to be not filled at the point of time the init event is triggered.

Basically I have my VerticalTabs element, which shows the content via {!v.body}

<div class="slds-vertical-tabs">
    <ul class="{!'slds-vertical-tabs__nav '+ (v.showHeader?'':'slds-hide')}" role="tablist" aria-orientation="vertical">
        {!v.header}
    </ul>
    {!v.body}
</div>

The tab structure is defined via a VerticalTab component

<div class="{#'slds-vertical-tabs__content slds-'+ (v.index==0?'show':'hide')}" id="{#'slds-vertical-tabs-' + v.index}" role="tabpanel" aria-labelledby="{#'slds-vertical-tabs-' + v.index + '__nav'}" aura:id="verticalTab">
    <div class="slds-text-longform">
        <aura:if isTrue="{#showTitle}">
            <h3 class="slds-text-heading_medium">{#v.title}</h3>
        </aura:if>
        <p>{!v.body}</p>
    </div>
  </div>

based on the body, I want to dynamically create the tabbar header. This is to be done dynamically via the controller iterating over the body:

init : function(component, event, helper) {
        console.log("init VerticalTabs");
        var body = component.get("v.body");
        var barComponents = [];
        for (var i=0, len = body.length; i<len; i++) {
            var title = body[i].get("v.title");
            console.log(title);
            body[i].set("v.index", i);
            barComponents.push(["aura:html", {
                "tag": "li",
                "HTMLAttributes": {
                    "title": title,
                    "class": "slds-vertical-tabs__nav-item " + (i==0?'slds-is-active':''),
                    "role": "presentation"
                }
            }]);
            barComponents.push(["aura:html", {
                "tag": "a",
                "body": title,
                "HTMLAttributes": {
                    "class": "slds-vertical-tabs__link",
                    "role": "tab",
                    "tabindex": (i==0?"0":"-1"),
                    "aria-selected": (i==0?"true":"false"),
                    "aria-controls": "slds-vertical-tabs-" + i,
                    "id": "slds-vertical-tabs-"+ i +"__nav",
                    "onclick": component.getReference("c.changeTab")
                }
            }]);
        }
        if (len > 1)
            component.set("v.showHeader", true);
        $A.createComponents(barComponents, function (components, status, errorMessage) {
            if (status === "SUCCESS") {
                var navbar = [];
                for (var i=0, len = components.length; i<len; i+=2) {
                    components[i].set("v.body", components[i+1]);
                    navbar.push(components[i]);
                }
                component.set("v.header", navbar);
            }
            else {
                console.log(errorMessage);
                //this.displayToast("Error", "Failed to create list components.");
            }
        });

next part is loading the vertical tabs via a wrapping component:

<aura:component implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="test" type="Object[]" />

    <c:VerticalTabs>
        <aura:iteration items="{!v.test}" var="q">
            <c:VerticalTab title="{!q}">
                <div>{!q}</div>
            </c:VerticalTab>
        </aura:iteration>
    </c:VerticalTabs>
</aura:component>

But it does look like this data is loaded after the initial init of the body. Due to the nature of aura:iteration it looks like the body does not get updated and I cannot receive the loaded verticalTab. This results in nothing being displayed.

Is there a more proper way of dynamically creating the content? How can I build my dynamic tabs? If I hard-code the VerticalTabs it is working flawless. Otherwise, it does not recognize the change in the v.body :/

nico

Best Answer

issue solved by forcing a re-render through

<aura:if isTrue="{!v.test.length>0}">
....
</aura:if>