SwiftUI - how to respond to TextField onCommit in an other View?

Viewed 663

I made a SearchBarView view to use in various other views (for clarity, I removed all the layout modifiers, such as color and padding):

struct SearchBarView: View {
    @Binding var text: String
    @State private var isEditing = false
    
    var body: some View {
        HStack {
            TextField("Search…", text: $text, onCommit: didPressReturn)
                 .overlay(
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                        
                        if isEditing {
                            Button(action: {
                                self.text = ""
                            }) {
                                Image(systemName: "multiply.circle.fill")
                            }
                        }
                    }
                )
    }
    
    func didPressReturn() {
        print("did press return")
    }
}

It looks and works great to filter data in a List.

But now I'd like to use the SearchBarView to search an external database.

struct SearchDatabaseView: View {
    @Binding var isPresented: Bool
    @State var searchText: String = ""

    var body: some View {
        NavigationView {
            VStack {
                SearchBarView(text: $searchText)
                // need something here to respond to onCommit and initiate a network call.

            }
            .navigationBarTitle("Search...")
            .navigationBarItems(trailing:
                Button(action: { self.isPresented = false })  {
                    Text("Done")
            })
        }
    }
}

For this, I only want to start the network access when the user hits return. So I added the onCommit part to SearchBarView, and the didPressReturn() function is indeed only called when tapping return. So far, so good.

What I don't understand is how SearchDatabaseView that contains the SearchBarView can respond to onCommit and initiate the database searh - how do I do that?

1 Answers

Here is possible approach

struct SearchBarView: View {
    @Binding var text: String
    var onCommit: () -> () = {}   // inject callback

    @State private var isEditing = false
    
    var body: some View {
        HStack {
            TextField("Search…", text: $text, onCommit: didPressReturn)
                 .overlay(
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                        
                        if isEditing {
                            Button(action: {
                                self.text = ""
                            }) {
                                Image(systemName: "multiply.circle.fill")
                            }
                        }
                    }
                )
    }
    
    func didPressReturn() {
        print("did press return")
       // do internal things...

       self.onCommit()      // << external callback
    }
}

so now in SearchDatabaseView you can

VStack {
    SearchBarView(text: $searchText) {
      // do needed things here ...
    }
}
Related