Dennis Bauszus
Dennis Bauszus

Reputation: 1792

Select a row programmatically using tabulator selectRow method

I am using tabulator to create tables on my website. I can select rows by clicking on them and I can select all rows using the tabulator.selectRow() method.

According to the documentation:

To select a specific row you can pass the any of the standard row component look up options into the first argument of the function.

I have seen this a few times but there is no working example. Does anybody know how the row component look up options need to be provided?

Let's say I have rows which have a name field.

I want to select the row where name == 'dennis'.

The documentation suggests that I can pass a lookup option in the selectRow() argument. There is just no example or any indication to expected syntax for the argument.

I currently have this working like so which does not seem to be most intuitive way.

table.getRows().forEach(row => {
  if (row.getData().name == 'dennis') row.toggleSelect();
});

Or like so:

params.layer.tableView.table.getRows()
    .filter(row => row.getData().name == 'dennis')
    .forEach(row => row.toggleSelect());

Upvotes: 1

Views: 3865

Answers (2)

Gerhard Liebenberg
Gerhard Liebenberg

Reputation: 444

Thank you for your post Dennis.

Here is a working example for Tabulator 6.2.

After a cell in the nested table is updated, the code updates other values in the same nested row, as well as in the parent row.

I added many comments to explain the functionality.

To test, run the following code in a browser and change any Qty value in a nested row:

<html>
<head>
<link href="https://unpkg.com/[email protected]/dist/css/tabulator.min.css" rel="stylesheet">
</head>
<body>   
<div id="example-table"></div> 
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/js/tabulator.min.js"></script>
<script>
    //define some sample data, with the sub-table data held in the subtable parameter
    var tableData = [
        {
            invoiceId: 1, customer: "Bob", invoiceTotal: "",
            invoiceRows: [
                { itemName: "Bread", qty: 3, price: 2, itemTotal: "", invoiceId: 1 }
            ],
        },
        {
            invoiceId: 2, customer: "Ann", invoiceTotal: "",
            invoiceRows: [
                { itemName: "Tyres", qty: 4, price: 100, itemTotal: "", invoiceId: 2 },
                { itemName: "Gas",   qty: 1, price: 30,  itemTotal: "", invoiceId: 2 }
            ],
        },
        {
            invoiceId: 3, customer: "Jim", invoiceTotal: "",
            invoiceRows: [
                { itemName: "Wine",   qty: 2, price: 4, itemTotal: "", invoiceId: 3 },
                { itemName: "Cheese", qty: 7, price: 3, itemTotal: "", invoiceId: 3 }
            ],
        },
    ];

    let table = new Tabulator("#example-table", {
    height:400,
        data:tableData,
        layout:"fitDataFill",
        columns:[
            { title: "Invoice Id", field:"invoiceId"},
            { title: "Customer", field: "customer" },
            { title: "Invoice Total", field: "invoiceTotal",
                formatter: function (cell, formatterParams, onRendered) {
                    // Sum the values of the nested rows
                    let rowData = cell.getRow().getData();
                    let invoiceRows = rowData['invoiceRows'];
                    let varInvoiceCost = 0;
                    let itemCount = Object.keys(invoiceRows).length                    
                    for (let i = 0; i < itemCount; i++) {
                        let itemObj = invoiceRows[i];
                        let varQty = 0;
                        let varPrice = 0;
                        Object.entries(itemObj).forEach(([key, value]) => {
                            if (key == 'qty') {
                                varQty = value;
                            }
                            if (key == 'price') {
                                varPrice = value;
                            }
                        });
                        varInvoiceCost += (varQty * varPrice);
                    }
                    return varInvoiceCost;
                },
            },
        ],
        rowFormatter: function (row) {
            //create and style holder elements
            var holderEl = document.createElement("div");
            var tableEl = document.createElement("div");

            // Remove nested table - if exists.
            // Without this, the parent row will duplicate the
            // nested table, each time you update the parent row.
            holderEl.classList.add("nested-table")
            var el = row.getElement();
            var nested = el.getElementsByClassName("nested-table");
            for (let child of nested) {
                child.parentNode.removeChild(child);
            }            

            holderEl.style.boxSizing = "border-box";
            holderEl.style.padding = "10px 30px 10px 10px";
            holderEl.style.borderTop = "1px solid #333";
            holderEl.style.borderBotom = "1px solid #333";
            tableEl.style.border = "1px solid #333";
            holderEl.appendChild(tableEl);
            row.getElement().appendChild(holderEl);
            var subTable = new Tabulator(tableEl, {
                layout: "fitColumns",
                data: row.getData().invoiceRows,
                columns: [
                    { title: "Invoice Id", field: "invoiceId", }, // hide with visible:false,
                    { title: "Item Name", field: "itemName" },
                    { title: "Qty", field: "qty",

                        // Editor is used to edit the Qty value
                        editor: function (cell, onRendered, success, cancel, editorParams) {
                            let cellValue = cell.getValue();
                            let input = document.createElement("input");
                            input.setAttribute("type", "text");
                            input.value = typeof cellValue !== "undefined" ? cellValue : "";

                            onRendered(function () {
                                input.focus();
                            });

                            //when the value has been set, trigger the cell to update
                            function successFunc() {
                                // Update backend via Ajax if needed
                                // Call success(input.value) from Ajax.done()
                                success(input.value); // Update the screen
                            }
                            input.addEventListener("change", successFunc);
                            input.addEventListener("blur", successFunc);

                            return input;
                        },

                        // cellEdited is triggered after a Qty value was changed
                        cellEdited: function (cell) {
                            // Update the value of itemTotal in the nested row, which will
                            // trigger its formatter to recalculate and display
                            // its new value (based on the new Qty in the nested row).
                            let row = cell.getRow();
                            let varQty = row.getCell('qty').getValue();
                            let varPrice = row.getCell('price').getValue();
                            let varItemTotal = varQty * varPrice;
                            row.update({ "itemTotal": varItemTotal })

                            // Update the value of invoiceTotal in the parent row.
                            // Retrieve the parent row based on invoiceId in the nested row.
                            // Change the value of invoiceTotal in the parent row's DOM, which
                            // will trigger the invoiceTotal formatter to recalculate and display
                            // its new value (based on the new values in the nested rows).
                            // ***Note***
                            // Since the formatter will calculate the value to display,
                            // based on the values of the nested rows (not invoiceTotal),
                            // you could technically store any value in invoiceTotal,
                            // as long as its a different value than before (to trigger the
                            // formatter). To illustrate this, the following statements update
                            // the value of invoiceTotal with the current timestamp, but the
                            // formatter will still display the correct output (we could have
                            // done the same with itemTotal above).
                            // However, if you later retrieve the value of invoiceTotal, you
                            // will get the timestamp stored in the DOM, and not the value which
                            // the formatter returned (displayed on the screen).
                            // Ps. This is just to explain why console.log() sometimes outputs 
                            // different values from what are displayed on your screen.
                            let varInvoiceId = row.getCell('invoiceId').getValue();
                            let parentRow = table.getRows().find(row => {
                                return row.getCell('invoiceId').getValue() == varInvoiceId;
                            });
                            parentRow.update({ "invoiceTotal": Date.now() }); // use timestamp
                        },
                    },
                    { title: "Price", field: "price" },
                    {
                        title: "Item Total", field: "itemTotal",
                        formatter: function (cell, formatterParams, onRendered) {
                            let varQty = cell.getRow().getCell('qty').getValue();
                            let varPrice = cell.getRow().getCell('price').getValue();
                            return varQty * varPrice;
                        },
                    },
                ]
            })
        },

    });

</script>
</body>
</html>

Upvotes: 0

Dennis Bauszus
Dennis Bauszus

Reputation: 1792

I got there in the end with help via github. #1749

The bit which cleared this up for me was this:

Any function that takes a component as an argument will also attempt to find that component based on the value provided if it is not a component itself.

Here as an example to select my row.

table.selectRow(table.getRows().filter(row => row.getData().name == 'Dennis'));

Upvotes: 4

Related Questions