Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Display API call data to new View

Attempting to display text to a view once my API call is complete. When a user submits there textfield, in onSubmit, I save the variable to my Binding foodName, which then gets passed to the new View (searchResultsView) If I display the data as Text, it works, but once I attempt to pass the data and display it in a separate view it does not.

My guess is I’m loading the view before the api call (or I could be completely off with my guess which I probably am). Any feedback would be helpful. Thank you.

API CALL

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class FoodApiSearch: ObservableObject{
    @Published var foodDescription = ""
    //will search for user Input
    func searchFood(userItem: String){
       //calls api search
        guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/foods/search?query=\(userItem)&dataType=&pageSize=1&pageNumber=1&api_key=***tDvDZVOy8cqG") else {return}
        
        URLSession.shared.dataTask(with: url) { (data, _,_) in
            let searchResults = try! JSONDecoder().decode(APISearchResults.self, from: data!)
            
            DispatchQueue.main.async {
                for item in searchResults.foods{
                        self.foodDescription = item.foodDescription ?? "food not valid"
                        print(self.foodDescription)
                    }
               
                }
        }
        .resume()
    }
}

Struct that calls SearchResultsView

struct testA: View {
    //Textfield
    @State var userFoodInput = ""
    @State private var didUserSearch = false
    //will store api var of foodName
    @StateObject private var foodApi = FoodApiSearch()
    //send to food results view
    @State private var  foodName = ""
    var body: some View {
            VStack{
                TextField("enter first name", text: $userFoodInput)
                    .onSubmit {
                        didUserSearch = true
                        foodApi.searchFood(userItem: userFoodInput)
                        foodName = foodApi.foodDescription
                    }
                
                FoodSearchResultsView(foodName: $foodName, userSearch: $didUserSearch)
        }
    }
}

SearchResultsView (view being called)

struct FoodSearchResultsView: View {
    //calls API
    @StateObject private var foodApi = FoodApiSearch()
    @State private var searchResultsItem = ""
    @Binding var foodName: String
    //if toggled, will display, binded to search bar
    @Binding var userSearch: Bool
  
    var body: some View {
        if userSearch{
            VStack{
                Text("Best Match")
                HStack{
                    VStack(alignment: .leading){
                        Text(foodName)
                        Text("1 Cup")
                            .font(.caption)
                            .offset(y:8)
                        }
                            .foregroundColor(.black)
                    Spacer()
                    Text("72 Cals")
                }
                
                .frame(width:225, height:50)
                .padding([.leading, .trailing], 45)
                .padding([.top, .bottom], 10)
                .background(RoundedRectangle(
                    cornerRadius:20).fill(Color("LightWhite")))
                .foregroundColor(.black)
                
                Button("Add Food"){
                   userSearch = false
                }
                .padding()
            }
            .frame(maxWidth:.infinity, maxHeight: 700)
        }
    }
}

>Solution :

Your suspicion was about right:

when you do:

foodName = foodApi.foodDescription

the network call did not finish yet.

Restructure your code. there is no need for the foodName variable as you have allready one in your FoodApiSearch. Pass that on to your subview and access it there. As soon as the network call completes it should update your view and show the result.

struct testA: View {
    //Textfield
    @State var userFoodInput = ""
    @State private var didUserSearch = false
    //will store api var of foodName
    @StateObject private var foodApi = FoodApiSearch()
    //send to food results view
    //@State private var  foodName = ""
    var body: some View {
            VStack{
                TextField("enter first name", text: $userFoodInput)
                    .onSubmit {
                        didUserSearch = true
                        foodApi.searchFood(userItem: userFoodInput)
//                        foodName = foodApi.foodDescription
                    }
                
                FoodSearchResultsView(userSearch: $didUserSearch)
                    .environmentObject(foodApi)
        }
    }
}

struct FoodSearchResultsView: View {
    //calls API
    @EnvironmentObject private var foodApi: FoodApiSearch
    @State private var searchResultsItem = ""
//    @Binding var foodName: String
    //if toggled, will display, binded to search bar
    @Binding var userSearch: Bool
  
    var body: some View {
        if userSearch{
            VStack{
                Text("Best Match")
                HStack{
                    VStack(alignment: .leading){
                        Text(foodApi.foodDescription)
                        Text("1 Cup")
                            .font(.caption)
                            .offset(y:8)
                        }
                            .foregroundColor(.black)
                    Spacer()
                    Text("72 Cals")
                }
                
                .frame(width:225, height:50)
                .padding([.leading, .trailing], 45)
                .padding([.top, .bottom], 10)
                .background(RoundedRectangle(
                    cornerRadius:20).fill(Color("LightWhite")))
                .foregroundColor(.black)
                
                Button("Add Food"){
                   userSearch = false
                }
                .padding()
            }
            .frame(maxWidth:.infinity, maxHeight: 700)
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading