# List with Generic Filter

**URL:** <https://discourse.elm-lang.org/t/list-with-generic-filter/9343>\
**Category:** Request Feedback\
**Created:** [September 21, 2023, 4:28pm UTC](https://discourse.elm-lang.org/t/list-with-generic-filter/9343 "2023-09-21T16:28:01Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![spruce\_moose](https://avatars.discourse-cdn.com/v4/letter/s/ed8c4c/32.png) [@spruce\_moose](https://discourse.elm-lang.org/u/spruce_moose)\
**Post date:** [September 21, 2023, 4:28pm UTC](https://discourse.elm-lang.org/t/list-with-generic-filter/9343/1 "2023-09-21T16:28:01Z")

</div>

Hi All,

I’m pretty new to Elm and have created a simple function for displaying a list of _things_ alongside a search box. When the user types into the search box, the list is then filtered according to some passed in function.

The function itself is below and I’ve posted a quick example of using it on [ellie](https://ellie-app.com/nYJQqwbNK8Ta1).

I was just wondering if this looks okay or if I’m doing something crazy wrong. The type signature is pretty gnarly so makes me think there’s something better I could be doing - I tried hiding some of the complexity in the FilterConfg object but I’m not sure if that’s the correct approach.

Any feedback would be much appreciated 😄

```elm
viewFilter : FilterConfig msg -> (a -> ( String, Html msg )) -> (String -> a -> Bool) -> List a -> List (Html msg)
viewFilter config viewListItem matches charlist =
    [Html.div [ Attr.class "filter"]
        [Html.label [ Attr.for config.inputID] [Html.text <| config.inputLabel ++ ":"]
        , Html.input
            [ Attr.placeholder config.inputPlaceholder
            , Attr.id config.inputID
            , Attr.value config.inputValue
            , Attr.type_ "text"
            , Attr.autocomplete False
            , Events.onInput config.inputEvent
            ]
            []
        ]
    , Html.Keyed.ol [] <|
        List.map viewListItem <|
            List.filter (matches config.inputValue) charlist
    ]

type alias FilterConfig msg =
    { inputID : String
    , inputLabel : String
    , inputPlaceholder : String
    , inputValue : String
    , inputEvent : String -> msg
    }

```

---

<div class="post-metadata">

**Author:** ![lydell](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lydell/32/178_2.png) [@lydell](https://discourse.elm-lang.org/u/lydell)\
**Post date:** [September 21, 2023, 6:39pm UTC](https://discourse.elm-lang.org/t/list-with-generic-filter/9343/2 "2023-09-21T18:39:12Z")

</div>

It looks good! ⭐

The type annotation might look less intimidating if you move `viewListItem` and `matches` into `FilterConfig` as well.

Since you render the results in an `<ol>`, each child needs to be a `<li>`. With this setup, each caller needs to be careful to implement `viewListItem` so that it renders a `<li>`. If you want to guarantee correct markup, you could have `viewFilter` render the `<li>` always.

---

<div class="post-metadata">

**Author:** ![spruce\_moose](https://avatars.discourse-cdn.com/v4/letter/s/ed8c4c/32.png) [@spruce\_moose](https://discourse.elm-lang.org/u/spruce_moose)\
**Post date:** [September 21, 2023, 8:58pm UTC](https://discourse.elm-lang.org/t/list-with-generic-filter/9343/3 "2023-09-21T20:58:51Z")

</div>

Thanks lydell!

I think I’ll add the `matches` filter to the config so that the function just takes a configuration, a way to display an item, and the list of items. It feels like there’s a fuzzy line between supplying everything in separate arguments vs. just giving a function a mega object.

Good point about the `<li>`. I did it this way so it was easy to add attributes from the calling function. I suppose a way to do that would be to change the `viewListItem` to return the Html content and attributes separately and then `viewFilter` can split these out (along with the key) and build the `<li>` itself. Something like [this](https://ellie-app.com/nYPmK6BZ3g4a1)?

```elm
type alias FilterConfig msg a =
    { ...
    , filterFn : String -> a -> Bool
    }

type alias FilterItem msg =
    { key : String
    , attrs : List (Html.Attribute msg)
    , content : List (Html msg)
    }

viewFilter : FilterConfig msg a -> (a -> FilterItem msg) -> List a -> List (Html msg)
viewFilter config viewListItem charlist =
    [Html.div [ Attr.class "filter"]
      ...
    , Html.Keyed.ol [] <|
        List.map toKeyedLi <|
        List.map viewListItem <|
        List.filter (config.filterFn config.inputValue) charlist
    ]

toKeyedLi: FilterItem msg -> (String, Html msg)
toKeyedLi filteritem =
    (filteritem.key, Html.li filteritem.attrs filteritem.content)

```

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [October 1, 2023, 8:58pm UTC](https://discourse.elm-lang.org/t/list-with-generic-filter/9343/4 "2023-10-01T20:58:54Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
