15

I am building a List based on my elements in an array I fetched before.

I am fetching all the entities.. when the user makes a search in the search bar, I want to filter my List. I am NOT doing a new FetchRequest, I just want to filter my objects.

That is the code I am using at the moment:

List(selection: $selectedDocument)
{
    ForEach(self.documentItems, id: \.self) { document in
        HStack(spacing: 0)
        {
            if (self.checkSearchString(document: document))
            {
                ListRow(document: document).tag(document)
            }
    }

I am having a List, then my ForEach loop. In that loop, I want to decide if I show that element or not. The problem is, that even if I do not want to show the element, there is still a small view inside my List. I know why, it is because I still render that HStack(). I basically need to drag that HStack() inside my If, however that is not working for me. I think it is because I need to render a view inside my List. But how can I contiuue my ForEach without rendering something.

That is what I want to achieve, BUT it is not working:

 List(selection: $selectedDocument)
 {
     ForEach(self.documentItems, id: \.self) { document in
         if (self.checkSearchString(document: document))
         {
             HStack(spacing: 0)
             {
                 ListRow(document: document).tag(document)
             }
         }

Thanks in advance!

0

3 Answers 3

19

filter your data BEFORE passing it to ForEach constuctor.

ForEach(self.documentItems.filter {self.checkSearchString(document: $0)}, id: \.self) { document in
    HStack(spacing: 0)
        {
            ListRow(document: document).tag(document)
        }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is what Apple recommends as well, source WWDC 23 session Demystify SwiftUI performance: developer.apple.com/wwdc23/10160?time=951 When inside of a List or Table they advise filtering the collection before passing it into the ForEach instead of having an if statement inside the ForEach because it keeps the number of views in the ForEach constant. Using the if statement "results in list needing to build all the views to retrieve the row identifiers because it doesn't know how many views each element resolves to."
13

You need to use Group to wrap different views provided by condition, like below

 ForEach(self.documentItems, id: \.self) { document in
   Group {
     if (self.checkSearchString(document: document))
     {
         HStack(spacing: 0)
         {
             ListRow(document: document).tag(document)
         }
     }
     else 
     {
        EmptyView()
     }
   }
 }

1 Comment

Does returning an EmptyView() hide the ForEach item?
0
List(selection: $selectedDocument)
{
    ForEach(self.documentItems, id: \.self) { document in

       self.checkSearchString(document: document) ?  extractedHstack() : emptyView()

    }

Extract your hstack and use a trinary with an empty view. Let me know if this works I did this from memory no IDE on this computer.

1 Comment

We tried that.. it works when we use it like that self.checkSearchString(document: document) ? EmptyView() : EmptyView() But if we replace the first EmptyView() with our view, it is not working anymore

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.