I am trying to make a name search functionality in a Compose project. I have a list of DummyClient
, which I am using as my data source on a view model. I am trying to search this list, so the updated result can be shown on a LazyColumn
, which is not returning any error but providing unexpected results.
class ClientViewModel : ViewModel() {
private var _clients = MutableLiveData(dummyClients)
val clients: LiveData<List<DummyClient>>
get() = _clients
fun searchClients(name: String) {
val foundClients: List<DummyClient?> = listOf(dummyClients.find {
it.name.contains(name)
})
_clients.value === foundClients
}
}
This ViewModel is passed to the ClientDirectoryScreen
composable from the navigation, which displays a search bar and the client list on a LazyColumn
:
val clientViewModel: ClientViewModel = ViewModel()
...
composable(Screen.Clients.route) {
ClientDirectoryScreen(
...
clientViewModel = clientViewModel
)
}
@Composable
fun ClientDirectoryScreen(
...
clientViewModel: ClientViewModel
) {
val clients by clientViewModel.clients.observeAsState(listOf())
val showSearchBar by clientViewModel.showSearchBar.observeAsState(false)
if (clients.isNotEmpty()) {
Column {
// show the search bar on search icon click
if (showSearchBar) ClientSearchCard(clientViewModel)
LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) {
items(clients) { client ->
ClientNameCard(client)
}
}
}
}
}
And the search bar invokes the search in the ViewModel, which doesn't reflect the search:
@Composable
fun ClientSearchCard(clientViewModel: ClientViewModel) {
var searchText by remember { mutableStateOf("") }
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
TextField(
value = searchText,
onValueChange = {
searchText = it
clientViewModel.searchClients(searchText)
},
label = { Text("Search:") },
modifier = Modifier.fillMaxWidth()
)
}
}
If I log the search result in the view model, the search doesn't provide the correct result. Also, I don't see any state change for the clients
variable in ClientDirectoryScreen
.
CodePudding user response:
find
will return you only one element, and the result is optional, because collection may have none.
Instead you can use filter
on the collection: it'll return all matching elements:
val foundClients = dummyClients.filter {
it.name.contains(name)
}
_clients.value = foundClients