For context, I'm working on a project where I have a table of ui choosers. No chooser can have a repeat value (unless nothing is selected), and when data is selected, it also propagates to other choosers, removing the option that was selected from the source chooser. There are other filters and rules, but I think that is enough to understand what I'm doing.
My setup looks something like this (I've trimmed it down to the most basic example):
type Msg
= UiMessage Ui.App.Msg
| SelectableChanged Selectable Ui.Chooser.Msg
type alias Selectable =
{ row : Int
, column : Int
, chooser : Ui.Chooser.Model
}
type alias Model =
{ app : Ui.App.Model
, selectables : List Selectable
, rows : List String
, columns : List String
, bigCollectionThatGetsConvertedIntoChooserItems : List a -- Has a string id and name field that can be mapped into Ui.Chooser.Items
}
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UiMessage subMsg ->
let
(nextApp, effect) = Ui.App.update subMsg model.app
in
( { model | app = nextApp }
, Cmd.map UiMessage effect
)
SelectableChanged selectable subMsg ->
let
(chooser, effect) = Ui.Chooser.update subMsg selectable.chooser
nextSelectable = { selectable | chooser = chooser }
replaceSelectable selectable =
if selectable.row == nextSelectable.row && selectable.column == nextSelectable.column then
nextSelectable
else
selectable
selectables =
model.selectables
|> List.map replaceSelectable
|> List.map myFiltersThatImNotGoingToWriteBecauseItCloudsThisExample
in
( { model | selectables = selectables }
, Cmd.map (SelectableChanged nextSelectable) effect
My big collection can have over 100 items, and the filters may map over each item a few times per update. I have a dynamic number of rows and columns, but it wouldn't be unusual for me to have 4 columns and 20 rows, so 100 cells, each with potentially 100 items in each cell.
Now to the problem; I only need to update the other choosers when a single chooser gets a new value, but SelectableChanged occurs with focus, open, close, blur, key movement, and select.
My current solution is to do something like:
selectables =
let
replacedSelectables =
model.selectables
|> List.map replaceSelectable
in
case subMsg of
Ui.Chooser.Select value ->
replacedSelectables
|> List.filter myFiltersThatImNotGoingToWriteBecauseItCloudsThisExample
_ ->
replacedSelectables
This occasionally does some sort of infinite loop that locks up my browser and ramps up memory use, but I'm sure with some tweaks it will do the right thing.
Optionally, I'm up for other solutions that don't require modifying the source in my elm-stuff
directory. I'm mostly an elm beginner, so maybe there is some other sort of map I can do, but it's not at all obvious to me right now.
So if my solution works (and I'm just doing something wrong), it would be great to have access to the various component Msg types so I can do my filtering on demand, and otherwise, you can close this issue and I'll ask on an elm message board for advice.