Home > front end >  Kotlin - Modify nested Data (Add item to List in an Object in another List in an Object)
Kotlin - Modify nested Data (Add item to List in an Object in another List in an Object)

Time:07-10

My User object has a List<Post>, each Post has a List<Tag>. Now I would like to add a Tag item to the List<Tag>.

User:

data class User(
    val id: String,
    val name: String,
    val posts: List<Post> = listOf()
)

Post:

data class Post(
    val id: Int,
    val name: String
    val tags: List<Tags> = listOf()
) 

Now I would like to update my MutableStateFlow containing the User object:

private val _userStateFlow: MutableStateFlow<User?> = MutableStateFlow(User())
val userStateFlow: StateFlow<User?> = _userStateFlow

To find the correct Post (containing the List<Tag> I want to update) I have the id of it (passedPostId)

val postsList = userStateFlow.value?.posts!!.toMutableList()
val tagsList = postsList.find { it.id == passedPostId }?.tags?.toMutableList()
tagsList.add(Tag("test"))

Now I got an updated tagsList but I need an updated postsList to pass it to my MutableStateFlow. I am not sure how to do it. This is how I update my MutableStateFlow:

_userStateFlow.update { it?.copy(posts = newPosts)

If I have the index of the post I want to update everything works fine, but In my Case I only can call .find because all i have is the id of the post.

val posts = userStateFlow.value?.posts!!.toMutableList()
posts[index] = posts[index].copy(tags = posts[index].tags.plus(Tag("test")
userStateFlow.value = userStateFlow.value?.copy(posts = posts)

CodePudding user response:

You can create a function to add a tag to your immutable Post object - may as well stick it inside the class:

data class Post(
    val id: Int,
    val name: String
    val tags: List<Tag> = listOf()
) {
    // copy this object, replacing the tag list with a copy that has the new one appended
    fun addTag(newTag: Tag) = copy(tags = tags   newTag)
}

Then you can do:

// alternative to putting it in the User class - whatever feels better
fun User.addTag(postId: Int, tag: Tag) =
    // copy this User, including copying its list of Posts
    // but any with a matching ID get the tag added
    copy(posts = posts.map { post ->
        if (post.id == postId) post.addTag(tag) else post
    })

and update with

userStateFlow.value = userStateFlow.value!!.addTag(passedPostId, Tag("test"))

Try it here if you like

CodePudding user response:

I fixed it by simply getting the index of the Post so I could use the code that worked before:

        val postPosition = postsList.indexOfFirst {
            it.id == passedPostId
        }

        postsList[postPosition] = postsList[postPosition].copy(tags = tagsList)
        _userStateFlow.update { it?.copy(posts = postsList)

I feel pretty stupid to not have thought of that in the first place.

  • Related