-1

I want user to select the city and district of that city. When I select the city I want to list the districts of that city in the pickerview. I also want to show the selection of the city and the selection of the district in Text.

struct locationView: View {


@State var selectedFrameworkIndex = 0
@State var tap1 : Bool = false

@ObservedObject var cityfetch = cityFetcher()

var selectedCityName: String? {
    if !cityfetch.cities.isEmpty && selectedFrameworkIndex < cityfetch.cities.count {
        return cityfetch.cities[selectedFrameworkIndex].city_name
    } else {
        return nil
    }
}

var body: some View {
    
          
            VStack{
                
                
                Picker(selection: $selectedFrameworkIndex, label: Text("")) {
                    ForEach(0 ..< cityfetch.cities.count, id: \.self) {
                        
                        Text(self.cityfetch.cities[$0].city_name)
                    }
                }.padding(.trailing, 50)
                    .id(UUID())
                
                
                Picker(selection: $selectedFrameworkIndex, label: Text("")){
                    ForEach(0 ..< cityfetch.cities.count, id: \.self) {
                        
                        Text(self.cityfetch.cities[$0].district_name)
                    }
                }.padding(.trailing, 50)
                    .id(UUID())
                
            }
            
            
            
            Text("Seçiminiz: \(selectedCityName ?? "")")
                .font(.system(size: 20, weight: .regular, design: .rounded))
            
            
        }

struct city : Decodable, Identifiable{

let id = UUID()
let city_id : Int
let city_name : String
let district_id : Int
let district_name : String
}

My class is following..

class cityFetcher : ObservableObject{

@Published var cities = [city]()


init() {
    loadCity()
    
}
func loadCity(){
    
    let url = URL(string: "https://raw.githubusercontent.com/midorikocak/turkish-cities-districts/master/data/il-ilce.json")
    URLSession.shared.dataTask(with: url!) { (data, response, error) in
        do{
            let cities = try JSONDecoder().decode([city].self, from: data!)
            DispatchQueue.main.async {
                self.cities = cities
                
            }
                
            
        }   catch{
            print("Error")
        }
    }.resume()
    
    
}

}

I also posting my JSON informations as an image.

enter image description here

Ozan
  • 39
  • 7
  • 1
    There are a lot of things you need to do here but for starters since your json contains duplicate cities you can't use it directly in a picker since it then would contain many "Adana" for instance. So you need to convert it into a different structure first to remove duplicate cities and so that you for each city can get the districts that belong to the city – Joakim Danielson Aug 14 '20 at 13:43

1 Answers1

0

Add function getUniqiueCities() in cityFetcher to create an array of unique cities and call this function after self.cities = cities. Create @Published var uniqueCities : [city] = [] in cityFetcher.

func getUniqiueCities() {
        var uniqueCities: [city] = []
        for city in self.cities {
            let isExists =  uniqueCities.contains{ item in
                return item.city_name == city.city_name
            }
            if !isExists {
              uniqueCities.append(city)
            }
        }
        self.uniqueCities =  uniqueCities
    }

Run a loop for unique cities and display districts based on unique city name. Update LocationView with below code

struct locationView: View {
    @State var selectedFrameworkIndex = 0
    @State var selectedCityIndex = 0
    @State var tap1 : Bool = false
    @ObservedObject var cityfetch = cityFetcher()

    var selectedCityName: String? {
        if !self.cityfetch.uniqueCities.isEmpty && selectedFrameworkIndex < self.cityfetch.uniqueCities.count {
            return self.cityfetch.uniqueCities[selectedFrameworkIndex].city_name
        } else {
            return nil
        }
    }

    var body: some View {
        VStack{
            Picker(selection: $selectedFrameworkIndex, label: Text("")) {
                ForEach(0 ..< self.cityfetch.uniqueCities.count, id: \.self) {
                    Text(self.cityfetch.uniqueCities[$0].city_name)
                }
            }.padding(.trailing, 50)
            .id(UUID())
            Picker(selection: $selectedCityIndex, label: Text("")){
                ForEach(0 ..< self.getFilteredDistricts().count, id: \.self) {
                    Text(self.getFilteredDistricts()[$0].district_name)
                }
            }.padding(.trailing, 50)
            .id(UUID())
            
        
                  
        Text("Seçiminiz: \(selectedCityName ?? "")")
            .font(.system(size: 20, weight: .regular, design: .rounded))
        }
    }
    
    func getFilteredDistricts() -> [city] {
        return self.cityfetch.cities.filter({$0.city_name == self.cityfetch.uniqueCities[selectedFrameworkIndex].city_name})
    }
    
}

UPDATE

As per comments, added code to get selectedDistrict:

var selectedDistrict: String? {
        if !self.getFilteredDistricts().isEmpty && selectedCityIndex < self.getFilteredDistricts().count {
            return self.getFilteredDistricts()[selectedCityIndex].district_name
        } else {
            return nil
        }
    }
Sona
  • 394
  • 3
  • 15
  • Thank you so much for your answer. It worked as I expected. Appreciated. – Ozan Aug 14 '20 at 16:32
  • I noticed that Text("Seçiminiz: \(selectedCityName ?? "")") part does not work correctly, when I choose different cities the value in the text does not change. I also want to display the district that is chosen into a text under the selected city name text. Could you please help me with that ? – Ozan Sep 11 '20 at 11:55
  • Let me check, will let you know – Sona Sep 11 '20 at 13:11
  • Updated my code, added code to get selected district. Please check and I haven't found any issues while displaying selected city name. It works perfectly for me. @Ozan – Sona Sep 11 '20 at 13:24
  • Thank you for your answer related selected district part. It works as I expected but there still is a problem related with selectedCityName part. If I change the city in the picker, text does not change with respect to that. – Ozan Sep 11 '20 at 21:16
  • The text for selectedCityName does not change as I expected. When I change the picker for the city, the related district names change, but cityName stays as it is. I couldn't figure out why it doesn't change. If you can help, I'd be appreciate. @Sona – Ozan Sep 22 '20 at 11:27
  • Do you have any suggestions regarding this issue ? @Sona – Ozan Sep 25 '20 at 19:14
  • I am not able to reproduce this issue @Ozan, For me its working – Sona Sep 28 '20 at 04:18
  • I have tried this solution but somehow my picker is not tappable @Sona – Mert Köksal Oct 02 '20 at 08:52