Home > Net >  Display API call data to new View
Display API call data to new View

Time:04-08

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

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)
        }
    }
}

CodePudding user response:

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)
        }
    }
}
  • Related