đŸ’ļ

Working with Tables

This tutorial covers how to work with tables

Setup

🌐

This developer tutorial targets a web app running on Replit: https://replit.com/@PixieBrixTodd/ReactSandbox. You can fork the project on Replit to try your own modifications!

When you run the application and navigate to the Table page, you'll see the following table (with different values, since they're randomly generated):

image

Creating the Basics

Creating a Button Foundation

The first thing we'll do is create a re-usable button for actions we want to add to the table

To find the selector, we can look at the element in the inspector. In this case, the .table-actions class looks like a robust selector as it's not used elsewhere on the page

image

To define to template, we'll find a button element in the inspector and copy it's outerHTML. By looking at the other buttons, we see a pattern in the class names (the site is using Bootstrap class names). With this knowledge we can choose some class names and place a {{{ caption }}} placeholder

image

apiVersion: v1
kind: extensionPoint
metadata:
  id: "@todd/sandbox/table-button"
  version: 0.0.1
  name: React table button
  description: Add a button to the Sandbox page
definition:
  type: menuItem
  reader: "@pixiebrix/session"
  isAvailable:
    matchPatterns: https://reactsandbox.pixiebrixtodd.repl.co/table
  defaultOptions:
    caption: "Action"
  containerSelector:
    - ".table-actions"
  template: |
    <button type="button" class="btn btn-info mx-2">{{{ caption }}}</button>

Table Reader

Next we'll define a table reader block. For this we'll use the jquery reader since we'll be reading directly from the HTML/DOM.

ℹī¸

Even though the application is built in React we can't use the react reader type to read the data from the table since it's not passed through as props to any of the React components (see the code here)

They key part of the definition is the multi: true which indicates that the sub-selectors will be used on each row

apiVersion: v1
kind: reader
metadata:
  id: "@todd/sandbox/table-reader-jquery"
  version: 0.0.1
  name: Sandbox table reader using JQuery
  description: Read React sandbox table using JQuery
definition:
  isAvailable:
    matchPatterns: https://reactsandbox.pixiebrixtodd.repl.co/table
  reader:
    type: jquery
    selectors:
      transactions:
        selector: tbody > tr
        multi: true
        find:
          txid: 
          # if we wanted to, we could cast the value to a number
          # type: number
          selector: td:nth-child(1)
          firstName: td:nth-child(2)
          lastName: td:nth-child(3)
          amount: td:nth-child(4)
          cleared: td:nth-child(5)

The resulting data will be an array of transactions as follows. Note that the data is read as a string for each field (to cast

{
	"transactions": [
		{"txid": "1", "firstName": "Bob", "lastName": "Newhart", "amount": "23 USD", "cleared": "No" 
	]
}

Table Operations

To transform/analyze our data, we'll use the @pixiebrix/jq brick is powered by the jq JSON processor.

📖

The jq documentation includes runnable examples for each of its operators

🎾

You can try jq in your browser with realtime feedback at https://jqplay.org

Extracting and Summing Values

To sum the amounts, we'll need to extract the values, convert them to numbers, and then add them. With jq, we can accomplish this with the capture, tonumber and add operators:

.transactions | map(.amount | capture("(?<val>\\d+) GBP") | .val | tonumber) | add

Checking Conditions

We can also use the jq brick to check whether conditions in the table are met. For example, we can use the all operator to check if any of the actions haven't been cleared yet:

.transactions | all(.cleared == "Yes")

Creating the Blueprint

Button to Sum the Amounts

extensionPoints:
  - id: "@todd/sandbox/table-button"
    label: Sum Amounts
    config:
      caption: Total
      action:
        - id: "@todd/sandbox/table-reader-jquery"
          config: {}
        - id: "@pixiebrix/jq"
          outputKey: total
          config:
            filter: '.transactions | map(.amount | capture("(?<val>\\d+) GBP") | .val | tonumber) | add'
        - id: "@pixiebrix/browser/alert"
          config:
            message: "Total amount: {{ @total }}"

Want to take it a step further? See how to convert the value to a different currency by

Button to Check if All Transactions are Cleared

extensionPoints:
  - id: "@todd/sandbox/table-button"
    label: Check Cleared
    config:
      caption: Cleared
      action:
        - id: "@todd/sandbox/table-reader-jquery"
          config: {}
        - id: "@pixiebrix/jq"
          outputKey: allCleared
          config:
            filter: '.transactions | all(.cleared == "Yes")'
        - id: "@pixiebrix/browser/alert"
          config:
	            message: "All cleared: {{ @allCleared }}"