Basic
The smallest possible table: four rows, six columns, no state. Ports examples/react/basic-use-table from TanStack Table.
Basic.elm
module Basic exposing (main)
{-| Ports `examples/react/basic-use-table/src/main.tsx`.
The smallest possible table: four literal rows, six columns, no feature
state at all. `Table.rowsFromList` still runs the whole pipeline; with an
empty `Table.State` every stage is the identity.
-}
import Browser
import Html exposing (Html, div, i, table, tbody, td, text, tfoot, th, thead, tr)
import Html.Attributes exposing (class, colspan)
import Table
import Table.Value as Value
-- DATA
type alias Person =
{ firstName : String
, lastName : String
, age : Int
, visits : Int
, status : String
, progress : Int
}
defaultData : List Person
defaultData =
[ Person "tanner" "linsley" 24 100 "In Relationship" 50
, Person "tandy" "miller" 40 40 "Single" 80
, Person "joe" "dirte" 45 20 "Complicated" 10
, Person "kevin" "vandy" 12 100 "Single" 70
]
-- CONFIG
config : Table.Config Person
config =
Table.config
[ Table.column "firstName" (.firstName >> Value.String)
|> Table.withHeader "First Name"
, Table.column "lastName" (.lastName >> Value.String)
|> Table.withHeader "Last Name"
, Table.column "age" (.age >> toFloat >> Value.Number)
|> Table.withHeader "Age"
, Table.column "visits" (.visits >> toFloat >> Value.Number)
|> Table.withHeader "Visits"
, Table.column "status" (.status >> Value.String)
|> Table.withHeader "Status"
, Table.column "progress" (.progress >> toFloat >> Value.Number)
|> Table.withHeader "Profile Progress"
]
-- MODEL
type alias Model =
{ state : Table.State
, data : List Person
}
init : Model
init =
{ state = Table.initialState
, data = defaultData
}
type Msg
= NoOp
update : Msg -> Model -> Model
update _ model =
model
-- VIEW
view : Model -> Html Msg
view model =
let
rowModel : Table.RowModel Person
rowModel =
Table.rowsFromList config model.state model.data
in
div [ class "demo-root" ]
[ table []
[ thead [] (List.map viewHeaderRow (Table.headerGroups config model.state))
, tbody [] (List.map (viewRow model.state) rowModel.rows)
, tfoot [] (List.map viewFooterRow (Table.footerGroups config model.state))
]
, div [ class "spacer-md" ] []
]
viewHeaderRow : Table.HeaderGroup Person -> Html Msg
viewHeaderRow group =
tr [] (List.map viewHeaderCell group.headers)
viewHeaderCell : Table.Header Person -> Html Msg
viewHeaderCell header =
th [ colspan (Table.headerColSpan header) ]
[ if Table.headerIsPlaceholder header then
text ""
else
text (headerLabel (Table.headerColumnId header))
]
viewFooterRow : Table.HeaderGroup Person -> Html Msg
viewFooterRow group =
tr [] (List.map viewFooterCell group.headers)
viewFooterCell : Table.Header Person -> Html Msg
viewFooterCell header =
-- No column in this example declares a footer, so, exactly like the
-- React example, the `<tfoot>` row renders empty cells.
th [ colspan (Table.headerColSpan header) ]
[ text
(Table.findColumn config (Table.headerColumnId header)
|> Maybe.andThen Table.columnFooter
|> Maybe.withDefault ""
)
]
headerLabel : String -> String
headerLabel columnId =
Table.findColumn config columnId
|> Maybe.andThen Table.columnHeader
|> Maybe.withDefault columnId
viewRow : Table.State -> Table.Row Person -> Html Msg
viewRow state row =
tr [] (List.map viewCell (Table.getAllCells config state row))
viewCell : Table.Cell -> Html Msg
viewCell cell =
td []
[ if cell.columnId == "lastName" then
i [] [ text (Value.toString cell.value) ]
else
text (Value.toString cell.value)
]
main : Program () Model Msg
main =
Browser.sandbox { init = init, update = update, view = view }