Home > database >  How to change the value of a var with a TextField SwiftUI
How to change the value of a var with a TextField SwiftUI

Time:11-16

I was trying to make a weather api call, the api call needs to have a location. The location that I pass is a variable, but now I want to change the location value based on a TextField's input.

I made the apiKey shorter just for safety measures. There's more code, but it's not relevant. I just need to know how to change the city variable that is on the WeatherClass using the TextField that is in the cityTextField View.

Thanks.

class WeatherClass: ObservableObject {
    @Published var weatherAddress: String = ""
    @Published var weatherDays: [WeatherDays] = []
    var city: String = ""
  
    func fetch() {
        let location = city
        let apiKey = "AP8LUYMSTHZ"
        
        let url = URL(string: "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/\(location)?key=\(apiKey)")!
            URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
                
            if let weather = try? JSONDecoder().decode(WeatherData.self, from: data) {
                DispatchQueue.main.async {
                    
                    self.weatherAddress = weather.resolvedAddress
                    self.weatherDays = weather.days
                }
            } else {
                print("City?")
            }
        }.resume()
    }//----------------------------------- End of fetch()
}
struct WeatherData: Decodable {
    let resolvedAddress: String
    let days: [WeatherDays]
}
struct WeatherDays: Hashable, Decodable {
    let datetime: String
    let tempmax: Double
    let tempmin: Double
    let description: String
}

struct cityTextField: View {
    
    @State var city: String = ""
    
    var body: some View {
       
            TextField("Search city", text: $city).frame(height:30).multilineTextAlignment(.center).background().cornerRadius(25).padding(.horizontal)
    } 
}

I already watched a lot of tutorials for similar things buts none of them really helped me.

CodePudding user response:

Try this approach using minor modifications to func fetch(_ city: String){...} to fetch the weather for the city in your TextField using .onSubmit{...}

struct ContentView: View {
    @StateObject var weatherModel = WeatherClass()
    
    var body: some View {
        VStack {
            cityTextField(weatherModel: weatherModel)
        }
    }
}

struct cityTextField: View {
    @ObservedObject var weatherModel: WeatherClass  // <-- here
    @State var city: String = ""
    
    var body: some View {
            TextField("Search city", text: $city)
            .frame(height:30)
            .multilineTextAlignment(.center)
            .background()
            .cornerRadius(25)
            .padding(.horizontal)
            .onSubmit {
                weatherModel.fetch(city)  // <-- here
            }
    }
}

class WeatherClass: ObservableObject {
    @Published var weatherAddress: String = ""
    @Published var weatherDays: [WeatherDays] = []

    func fetch(_ city: String) {  // <-- here
        let apiKey = "AP8LUYMSTHZ"
        
        // -- here
        let url = URL(string: "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/\(city)?key=\(apiKey)")!
        
            URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
            if let weather = try? JSONDecoder().decode(WeatherData.self, from: data) {
                DispatchQueue.main.async {
                    self.weatherAddress = weather.resolvedAddress
                    self.weatherDays = weather.days
                }
            } else {
                print("City?")
            }
        }.resume()
    }
}

Alternatively, as suggested by synapticloop, you could use this approach:

struct cityTextField: View {
    @ObservedObject var weatherModel: WeatherClass  // <-- here

    var body: some View {
        TextField("Search city", text: $weatherModel.city) // <-- here
            .frame(height:30)
            .multilineTextAlignment(.center)
            .background()
            .cornerRadius(25)
            .padding(.horizontal)
            .onSubmit {
                weatherModel.fetch()  // <-- here
            }
    }
}

class WeatherClass: ObservableObject {
    @Published var weatherAddress: String = ""
    @Published var weatherDays: [WeatherDays] = []
    @Published var city: String = "" // <-- here

    func fetch() {
        let apiKey = "AP8LUYMSTHZ"
        
        // -- here
        let url = URL(string: "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/\(city)?key=\(apiKey)")!
        
            URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
            if let weather = try? JSONDecoder().decode(WeatherData.self, from: data) {
                DispatchQueue.main.async {
                    self.weatherAddress = weather.resolvedAddress
                    self.weatherDays = weather.days
                }
            } else {
                print("City?")
            }
        }.resume()
    }
}
  • Related