[SalesForce] How to implement aura:iteration?

I have built a component that will accept a user input for dimensions for the size of a table they desire, and then the component will pull image URL's from an object that have been added and display them in a table. I have added a functionality of where the user can click through multiple images using the next/previous buttons. The way I have written the component is that the majority of the work is done in the controller. I want to be able to perform this same functionality but where the table is displayed through the component instead, where I will be able to move it towards using the lightning:grid instead of a data table. I have copied the code below so you can see what I am doing.

I am basically having trouble on how to write a nested aura:iteration statement with a table to where the user can dynamically change the size of the table, or I am thinking of the approach in the wrong direction.

Component

<aura:component controller="imageUrlDisplay" >

    <!-- attributes -->
    <aura:attribute name="imageHolder" type="Object" />
    <aura:attribute name="imgList" type="List"/>
    <aura:attribute name="recordId" type="String" />
    <aura:attribute name="totalImages" type="Integer" />
    <aura:attribute name="pageCounter" type="Integer" />
    <aura:attribute name="rows" type="Integer" />
    <aura:attribute name="cols" type="Integer" />
    <aura:attribute name="maxPage" type="Integer"/>    

    -->
    <!-- this is for a fancyish header for the page -->
    <lightning:card title="Tables">

        <!-- This is for the user to input how many rows and columns is desired -->
        <ui:inputText aura:id="cols" label="Enter Number of Columns" value="{!v.cols}"/>
        <ui:inputText aura:id="rows" label="Enter Number of Rows"  value="{!v.rows}"/>
        <ui:button label="Submit" press="{!c.doInit}"/>

        <div aura:id="target-div">
        </div>
        <br/>

        <ui:button aura:id="previous" label="Previous" press="{!c.prevClicked}"/>
        <ui:button aura:id="next" label="Next" press="{!c.nextClicked}"/>


    </lightning:card>
</aura:component>

Controller

({
    doInit : function(component, event, helper) {

        // variables
        var recId;
        var action = component.get("c.getImgUrl"); 
        var table = '';
        var rows = component.get("v.rows");
        var cols = component.get("v.cols");
        var displayNumber = rows * cols;

      //  var imgList;
        var pageCounter=1;
        var tableImageCounter =0;

        // setting value to recId
        action.setParams({
            recordId:recId
        });

        //All actions for the table are in this block of code
        action.setCallback(this, function(response){
            //sets all the url values into the variable which is being used as a list
           var imgList = response.getReturnValue();
           var keys = Object.keys(imgList);

           var totalImages = keys.length;
            console.log(totalImages);


            //for loops to populate table correctly
            for(var r=0; r<rows; r++){

                console.log("In first for loop");
                table +='<tr>';

                for(var c =1; c<= cols; c++){  
                    // to insure incrementing of the images is done properly regardless of table demensions

                    console.log("In second");                    
                    table +='<td >' + '<img src='+ '"' + imgList[tableImageCounter].imageUrlRich__c + '"' + 'style=' + '"'+'width:42px;height:42px;border:1px;'+'"'+ + '/>'+ '</td>';      
                    if(cols>rows){
                        tableImageCounter++;
                    }
                     else if(rows>cols){
                        tableImageCounter++;
                    }
                    else if(rows==cols){
                        tableImageCounter++;
                    }
                }
                // to insure incrementing of the images is done properly regardless of table demensions

                table +="</tr>"        
            } 

            var codeContent = '<table class=' +'"'+'slds-table slds-table_bordered slds-table_cell-buffer'+'"'+'>' + table + '</table>';
            component.find('target-div').getElement().innerHTML = codeContent;
            component.set("v.pageCounter", pageCounter);
            component.set("v.imgList", imgList);
            component.set("v.totalImages", totalImages);

        });

        $A.enqueueAction(action);
        console.log("Got to enqueue");

    },

    nextClicked : function(component, event, helper){

        var table = '';
        var rows = component.get("v.rows");
        var cols = component.get("v.cols");
        var displayNumber = rows * cols;
        var imgList = component.get("v.imgList");
        var pageCounter = component.get("v.pageCounter");
        pageCounter++;
        var totalImages = component.get("v.totalImages");
        var maxPage;
        var tableImageCounter;


        maxPage = totalImages/displayNumber;

        if((totalImages%displayNumber) != 0){
            maxPage++;
        }

        if(pageCounter == 2){ tableImageCounter = displayNumber+1;}
        if(pageCounter > 2){tableImageCounter = ((pageCounter *displayNumber)-displayNumber)+1;}
        // stops it from breaking where the pages exceeds number of items to display.
        if(pageCounter >= maxPage){tableImageCounter = (maxPage * displayNumber)-displayNumber+1;}


        //for loops to populate table correctly
        for(var r=0; r<rows; r++){

            console.log("In first for loop from next click");
            table +='<tr>';

            for(var c =1; c<= cols; c++){  
                // to insure incrementing of the images is done properly regardless of table demensions

                console.log("In second from next click");  
                if(imgList[tableImageCounter] == null){  
                    var btn = event.getSource();
                    btn.set("v.disabled", true);
                    break;
                }
                table +='<td >' + '<img src='+ '"' + imgList[tableImageCounter].imageUrlRich__c + '"' + 'style=' + '"'+'width:42px;height:42px;border:1;'+'"'+ + '/>'+ '</td>';     
                if(cols>rows){
                    tableImageCounter++;
                }
                // to insure incrementing of the images is done properly regardless of table demensions
                else if(rows>cols){
                    tableImageCounter++;
                }
                else if(rows==cols){
                    tableImageCounter++;
                }
            }

            table +="</tr>";        
        } 
        if(pageCounter != 1){
            var btn = component.find("previous");
            btn.set("v.disabled", false);
        }
            var codeContent = '<table class=' +'"'+'slds-table slds-table_bordered slds-table_cell-buffer'+'"'+'>' + table + '</table>';
        component.find('target-div').getElement().innerHTML = codeContent;      
        console.log("Got to enqueue from nextClicked");
        component.set("v.pageCounter", pageCounter);
        component.set("v.maxPage", maxPage);
    },

    prevClicked : function(component, event, helper){
        var table = '';
        var rows = component.get("v.rows");
        var cols = component.get("v.cols");
        var displayNumber = rows * cols;
        var imgList = component.get("v.imgList");
        var pageCounter = component.get("v.pageCounter");
        pageCounter--;
        var tableImageCounter;
        var maxPage = component.get("v.maxPage");


        if(pageCounter > 2){ tableImageCounter = ((pageCounter *displayNumber)-displayNumber)+1;}
        if(pageCounter == 2){tableImageCounter = ((displayNumber+1));}
        if(pageCounter <2){tableImageCounter=0;}


            //for loops to populate table correctly
            for(var r=0; r<rows; r++){

                console.log("In first for loop from next click");
                table +='<tr>';

                for(var c =1; c<= cols; c++){  
                    // to insure incrementing of the images is done properly regardless of table demensions
                    if(pageCounter == 1){                                                     
                    var btn = event.getSource();
                    btn.set("v.disabled", true);
                    }
                    console.log("In second from next click");                    
                    table +='<td >' + '<img src='+ '"' + imgList[tableImageCounter].imageUrlRich__c + '"' + 'style=' + '"'+'width:42px;height:42px;border:1;'+'"'+ + '/>'+ '</td>';     
                    if(cols>rows){
                        tableImageCounter++;
                    }
                    // to insure incrementing of the images is done properly regardless of table demensions
                    else if(rows>cols){
                        tableImageCounter++;
                    }
                        else if(rows==cols){
                            tableImageCounter++;
                        }
                }

                table +="</tr>"        
            } 
        if(pageCounter < maxPage){
            var btn = component.find("next");
            btn.set("v.disabled", false);
        }
            var codeContent = '<table class=' +'"'+'slds-table slds-table_bordered slds-table_cell-buffer'+'"'+'>' + table + '</table>';
            component.find('target-div').getElement().innerHTML = codeContent;    
            component.set("v.pageCounter", pageCounter);

    } 
})

Best Answer

Here's a very rough design that does what you want it to, mostly. It's got a few hiccups that need to be sorted out, but this should get you started.

<aura:application extends="force:slds">
    <aura:attribute name="page" type="String[]" default="[]" />
    <aura:attribute name="items" type="String[]" default="[]" />
    <aura:attribute name="rows" type="Integer" default="3" />
    <aura:attribute name="columns" type="Integer" default="3" />
    <aura:attribute name="colSize" type="Integer" default="4" />
    <aura:attribute name="pageNumber" type="Integer" default="1" />
    <aura:attribute name="maxPage" type="Integer" default="9" />

    <aura:handler name="init" value="{!this}" action="{!c.init}" />

    <lightning:input onchange="{!c.updateView}" value="{!v.columns}" type="range" min="1" max="6" label="Columns" name="cols" />
    <lightning:input onchange="{!c.updateView}" value="{!v.rows}" type="range" min="1" max="12" label="Rows" name="rows" />
    <lightning:input onchange="{!c.updateView}" value="{!v.pageNumber}" type="range" min="1" max="{!v.maxPage}" label="Page" name="pageNumber" />

    <lightning:layout horizontalAlign="spread" multipleRows="true">
        <aura:iteration items="{!v.page}" var="pageItem">
            <lightning:layoutItem size="{!v.colSize}">
                Item: {!pageItem}
            </lightning:layoutItem>
        </aura:iteration>
    </lightning:layout>
</aura:application>

({
    init: function(component, event, helper) {
        var items = [];
        while(items.length<100) {
            items.push(items.length+'');
        }
        component.set("v.items", items);
        var page = items.slice(0, 9);
        component.set("v.page", page);
        console.log(page);
    },
    updateView: function(component, event, helper) {
        var items = component.get("v.items"), cols = component.get("v.columns"),
            pageNum = component.get("v.pageNumber"), rows = component.get("v.rows"), 
            size = rows*cols, colSize = Math.floor(12/cols), 
            maxPage = Math.floor((items.length+(size-1))/size),
            page = items.slice((pageNum-1)*size, pageNum*size);
        component.set("v.page", page);
        component.set("v.colSize", colSize);
        component.set("v.maxPage", maxPage);
    }
})
Related Topic