NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

How to choose dynamically JSON content from the web?

Forums > Swift

I have this code to access to JSON that is online. It works well:

struct User: Codable {
    let name: String
    let email: String
}

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
        URLSession.shared.dataTask(with: url) { data, _, _ in
            if let data = data {
                let users = try? JSONDecoder().decode([User].self, from: data)

                print (users![0].name)
            }
        }.resume()

    }

}

I would like to do the same dynamically. I mean that the user can choose in a textField if he wants to pick up the information name, mail...

I tried many things. For instance: var hePicks = textField1.stringValue print (users![0].hePicks)

It seems that I cannot put a var there!. If I print print (users![0]) the information is there. How can I choose dynamically one of the fields?

1      

Hi @narcisG

The user do not pick from the JSON but from the downloaded Array. So it up to you which fields by added them to the struct User

1      

Ok. Then, how do you make that dynamic?. Please, how would you do it in my example?

I suppose the question is how to create a var/let inside the struct. Dynamically, create the var with what the user writes in the text field

1      

It depends on your UI. You do not use the "load" to change as in your code. I have done a little SwiftUI just to show, as I am quicker in that.

I changed your User struct a bit

struct User: Decodable, Identifiable {
    let id: Int
    let name: String
    let email: String

    enum SelectedDisplay {
        case name, email
    }
}

then this in ContentView

struct ContentView: View {
    @State private var users = [User]()
    @State private var selectedDisplay: User.SelectedDisplay = .name

    var body: some View {
        NavigationView {
            VStack {
                Picker("Select Display", selection: $selectedDisplay) {
                    Text("Name").tag(User.SelectedDisplay.name)
                    Text("Email").tag(User.SelectedDisplay.email)
                }
                .pickerStyle(SegmentedPickerStyle())
                .padding(.horizontal)

                List {
                    ForEach(users) { user in
                        VStack(alignment: .leading) {
                            if selectedDisplay == .name {
                                Text(user.name)
                            } else {
                                Text(user.email)
                            }
                        }
                    }
                }
            }
            .navigationTitle("Contacts")
            .onAppear(perform: load)
        }
    }

    func load() {
        let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                do {
                    users = try JSONDecoder().decode([User].self, from: data)
                } catch {
                    print(error.localizedDescription)
                }
            }
        }.resume()
    }
}

1      

I think I did no explain well. I simplified the case to ask the question here, but there are many options. Not only name an mail. I cannot solve the problem with a conditional if else.

The user writes in a text field what he wants. With that information I have to create the var/let inside the struct

1      

If I get this right You want the user to enter in a TextField some text that then become a property that is in code!

I do not think this is possible!

You will have to provide the list of the fields that the user can pick then use that information. Which I did in the Picker which then translate into code which displayed the results. As you said the my code was a sample of what you can do! There are many ways depending what you what to show.

You can change the enum

enum SelectedDisplay: String, CaseIterable {
    case name, email, company, address
}

and the Picker to this

Picker("Select Display", selection: $selectedDisplay) {
    ForEach(User.SelectedDisplay.allCases, id: \.self) { type in
        Text(type.rawValue.capitalized).tag(type)
    }
}
.padding(.horizontal)

then change if statement

switch selectedDisplay {
case .name:
    Text(user.name)
case .email:
    Text(user.email)
case .company:
    Text(user.company.name)
case .address:
    Text(user.address.street)
}

As the above code show by giving them what to choose then you can change on their choice. See Below with TextField

struct ContentView: View {
    @State private var users = [User]()
    @State private var selectedDisplay = ""

    var body: some View {
        NavigationView {
            Form {
                TextField("Select Field", text: $selectedDisplay)

                Section {
                    List {
                        ForEach(users) { user in
                            VStack(alignment: .leading) {
                                switch selectedDisplay.lowercased() {
                                case "name":
                                    Text(user.name)
                                case "email":
                                    Text(user.email)
                                case "company":
                                    Text(user.company.name)
                                case "address":
                                    Text(user.address.street)
                                default:
                                    Text("")
                                }
                            }
                        }
                    }
                }
            }
            .navigationTitle("Contacts")
            .onAppear(perform: load)
        }
    }

    func load() {
        let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                do {
                    users = try JSONDecoder().decode([User].self, from: data)
                } catch {
                    print(error.localizedDescription)
                }
            }
        }.resume()
    }
}

1      

Ok. I understand. To write all the options in my real case make things really complicated. I suppose that I will have to begin offering only a few things to choose to the user.

Thank you!

1      

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.