---
id: stream_message_search_list_controller
sidebar_position: 6
title: StreamMessageSearchListController
---

A Widget For Controlling A List Of Searched Messages

Find the pub.dev documentation [here](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageSearchListController-class.html)

### Background

The `StreamMessageSearchListController` is a controller class that allows you to control a list of searched messages.
`StreamMessageSearchListController` is a required parameter of the `StreamMessageSearchListView` widget.
Check the [`StreamMessageSearchListView` documentation](../03-stream_chat_flutter/stream_message_search_list_view.mdx) to read more about that.

### Basic Example

Building a custom message search feature is a common task. Here is an example of how to use the `StreamMessageSearchListController` to build a simple search list with pagination.

First of all we should create an instance of the `StreamMessageSearchListController` and provide it with the `StreamChatClient` instance.
You can also add a `Filter`, a list of `SortOption`s and other pagination-related parameters.

```dart
class SearchListPageState extends State<SearchListPage> {
  /// Controller used for loading more data and controlling pagination in
  /// [StreamMessageSearchListController].
  late final messageSearchListController = StreamMessageSearchListController(
    client: StreamChatCore.of(context).client,
  );
```

Make sure you call `messageSearchListController.doInitialLoad()` to load the initial data and `messageSearchListController.dispose()` when the controller is no longer required.

```dart
@override
void initState() {
  messageSearchListController.doInitialLoad();
  super.initState();
}

@override
void dispose() {
  messageSearchListController.dispose();
  super.dispose();
}
```

The `StreamMessageSearchListController` is basically a [`PagedValueNotifier`](./paged_value_listenable_builder.mdx) that notifies you when the list of responses has changed.
You can use a [`PagedValueListenableBuilder`](./paged_value_listenable_builder.mdx) to build your UI depending on the latest responses.

```dart
@override
Widget build(BuildContext context) => Scaffold(
      body: Column(
        children: [
          TextField(
            /// This is just a sample implementation of a search field.
            /// In a real-world app you should throttle the search requests.
            /// You can use our library [rate_limiter](https://pub.dev/packages/rate_limiter).
            onChanged: (s) {
              messageSearchListController.searchQuery = s;
              messageSearchListController.doInitialLoad();
            },
          ),
          Expanded(
            child: PagedValueListenableBuilder<String, GetMessageResponse>(
              valueListenable: messageSearchListController,
              builder: (context, value, child) {
                return value.when(
                  (responses, nextPageKey, error) => LazyLoadScrollView(
                    onEndOfPage: () async {
                      if (nextPageKey != null) {
                        messageSearchListController.loadMore(nextPageKey);
                      }
                    },
                    child: ListView.builder(
                      /// We're using the responses length when there are no more
                      /// pages to load and there are no errors with pagination.
                      /// In case we need to show a loading indicator or and error
                      /// tile we're increasing the count by 1.
                      itemCount: (nextPageKey != null || error != null)
                          ? responses.length + 1
                          : responses.length,
                      itemBuilder: (BuildContext context, int index) {
                        if (index == responses.length) {
                          if (error != null) {
                            return TextButton(
                              onPressed: () {
                                messageSearchListController.retry();
                              },
                              child: Text(error.message),
                            );
                          }
                          return CircularProgressIndicator();
                        }

                        final _item = responses[index];
                        return ListTile(
                          title: Text(_item.channel?.name ?? ''),
                          subtitle: Text(_item.message.text ?? ''),
                        );
                      },
                    ),
                  ),
                  loading: () => const Center(
                    child: SizedBox(
                      height: 100,
                      width: 100,
                      child: CircularProgressIndicator(),
                    ),
                  ),
                  error: (e) => Center(
                    child: Text(
                      'Oh no, something went wrong. '
                      'Please check your config. $e',
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
```

In this case we're using the [`LazyLoadScrollView`](./lazy_load_scroll_view.mdx) widget to load more data when the user scrolls to the bottom of the list.