0

I have below HTML

                <div>
                    <table class="slds-table slds-table_cell-buffer slds-table_bordered">
                        <thead>
                            <template for:each={pageDetailsHeaders} for:item="pageDetail">
                                <tr class="slds-line-height_reset" key={pageDetail}>
                                    <th scope="row">
                                        <div>
                                            {pageDetail}
                                        </div>
                                    </th>
                                </tr>
                            </template>
                        </thead>
                        <tbody>
                            <template for:each={pageDetailsData} for:item="pageDetail">
                                <tr key={pageDetail}>
                                    <td>
                                        <div>
                                            {pageDetail}
                                        </div>
                                    </td>
                                </tr>
                            </template>
                        </tbody>
                    </table>
                </div>

JS:

handlePageDetails() {
        let pageDetailsMap = new Map();
        this.showPageDetails = this.showPageDetails ? false : true;
        //if (this.showPageDetail === false) return;
        lineItemData.forEach(data => {
            let category = data.category ? data.category : 'Without Category';
            if (!pageDetailsMap.has(category)) {
                pageDetailsMap.set(category, 1);
            } else {
                let updatedValue = pageDetailsMap.get(category) + 1;
                pageDetailsMap.set(category, updatedValue);
            }
            if (!pageDetailsMap.has(data.testType)) {
                pageDetailsMap.set(data.testType, 1);
            } else {
                let updatedValue = pageDetailsMap.get(data.testType) + 1;
                pageDetailsMap.set(data.testType, updatedValue);
            }
        })
        pageDetailsMap.set('Total Products', lineItemData.length);
        pageDetailsMap.set('Total Visits', this.studyData.length);
        this.pageDetailsHeaders = Array.from(pageDetailsMap.keys());
        this.pageDetailsData = Array.from(pageDetailsMap.values());
        console.log(pageDetailsMap.entries());
    }

I tried to iterate map but didn't get any success so I converted keys and values in different array and then iterated on HTML and I am getting results as below

table image

table data and header should come side by side instead of all in one column, can anyone suggest any better approach to do the same.

6
  • Not sure if there was a reason for you to choose the standard HTML Table elements. Why not use lightning:datatable? – arut May 2 '20 at 11:26
  • Thank you for your response, but I am not sure if we can display headers vertically with lightning data table and also I cannot hard code the table headers because number of columns are dynamic, if you know we can achieve both of these with lighting data table then I would request you to please post an example as an answer. – gs650x May 2 '20 at 11:34
  • sorry...my bad....I guess I missed out read that last line in your question completely. – arut May 2 '20 at 11:44
  • Could you apply the following CSS and check it out? thead {float:left; width:20%} & tbody{float:left}. Note that this will work for a table that has only one data row (columns can be multiple). Looking at your example, I have assumed that you are displaying some kind of summary table that will not have more than 1 data row. You might need to modify the width% accordingly. After looking into the rendered HTML elements inside a lightning:datatable, I don't think it would be a good idea to try and style it for your requirement. – arut May 2 '20 at 12:54
  • thank you for the above CSS, it almost worked but table header and table data are not aligned – gs650x May 2 '20 at 15:38
0

Salesforce styles are expecting the th to be on the thead element to give the styles, and the problem you are facing is that thead rows are shown on the top.

You could try to play with css, but the second you have rows with more than one line, you might face some rendering issues.

My suggestion below is to have all the data inside the tbody, having the first cell as header (th) and the second as regular cell (td).

As per your last comment, I think that this could be closer to what you are looking for (note that you might have to edit some styles. I put one in-line so it looks closer to the standard, but I strongly recommend to use the .css file of the component, taking advantage of the fact that the header is in th. Feel free to copy the ones from SF thead>th)

    <div>
        <table class="slds-table slds-table_cell-buffer slds-table_bordered">
            <tbody>
                <template for:each={pageDetailsData} for:item="pageDetail">
                    <tr key={pageDetail.header}>
                        <th style="background-color: var(--lwc-tableColorBackgroundHeader,rgb(250, 250, 249))">
                            <div>
                                {pageDetail.header}
                            </div>
                        </th>
                        <td>
                            <div>
                                {pageDetail.value}
                            </div>
                        </td>
                    </tr>
                </template>
            </tbody>
        </table>
    </div>

.js ( I did not check if it compiles, but it gives you an idea. The idea is to have a list with two attributes, header and value

    handlePageDetails() {

        this.showPageDetails = this.showPageDetails ? false : true;
        //if (this.showPageDetail === false) return;

        // reduce goes over every element and passes an accumulator so you can keep track of your counters
        // I've used the operator || to give defaults to undefined variables (which saves you the trouble of all those "ifs"
        let pageDetailsMap = lineItemData.reduce((accumulator, data) => {

            let category = data.category || 'Without Category';

            accumulator.set(category, (accumulator.get(category) || 0) + 1);
            accumulator.set(data.testType, (accumulator.get(data.testType) || 0) + 1);

        }, new Map());

        pageDetailsMap.set('Total Products', lineItemData.length);
        pageDetailsMap.set('Total Visits', this.studyData.length);

        // .map iterates over all the items of the array replacing them by the returned value of the function. in this case the header gets replaced by a structure with a header field and a value field)
        this.pageDetailsData = Array.from(pageDetailsMap.keys()).map(key=>{
            return {
                header : key,
                value  : pageDetailsMap.get(key)
            };
        });
        console.log(pageDetailsMap.entries());
    }
3
  • Thank you for your response, but I am not sure if we can display headers vertically with lightning data table and also I cannot hard code the table headers because number of columns are dynamic, if you know we can achieve both of these with lighting data table then I would request you to please post an example as an answer. – gs650x May 2 '20 at 15:29
  • If I put tr outside the loop then it renders all the table data in a single row not parallel to table headers – gs650x May 2 '20 at 15:29
  • @gs650x I've modified my post, let me know if it looks closer to what you need – Sergio Alcocer May 2 '20 at 17:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.