johny
johny

Reputation: 3

Get value from JSON API response in SwiftUI Xcode

I need to post a https request to login view (SwiftUI), my code follow I have in getres.swift: so I neet to get value from response and put it in the text

      import Foundation
        import Combine

        struct result: Decodable {
           let res, ordercount, rate: String
        }

        class getres: ObservableObject {

          let objectWillChange = PassthroughSubject<getres, Never>()
        @Published var authenticated = ""
          @Published var todos = [result]() {
              didSet {
                   objectWillChange.send(self)
              }
           }

            func auth(username: String, password: String) {
            guard let url = URL(string: "http://company.com/auth.php") else { return }

            let body: [String: String] = ["username": username, "password": password]

            let finalBody = try! JSONSerialization.data(withJSONObject: body)

            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            request.httpBody = finalBody
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            URLSession.shared.dataTask(with: request) { (data, response, error) in


 guard let data=data else{return}


    let fineldata=try! JSONDecoder().decode(result.self, from: data)


        DispatchQueue.main.async {
            self.todos = [fineldata]
            self.authenticated=fineldata.res


        }


 print(fineldata)









    }.resume()
          }

        }

and in the login page I try to show other view

in this code I will get values from function as json response I will get ordercount and rate I put it in the other view

 import SwiftUI

    struct ContentView: View {

    @State private var username: String = ""
    @State private var password: String = ""

    @ObservedObject   var manager = getres()


    var body: some View {

        VStack(alignment: .leading) {

            if manager.authenticated == "2"{
                                        userdetails()
                                    }else{


            Text("Username")
            TextField("placeholder", text: $username)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .border(Color.green)
                .autocapitalization(.none)

            Text("Password")
            SecureField("placeholder", text: $password)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .border(Color.green)

            Button(action: {

                self.manager.auth(username: self.username, password: self.password)

            }) {
                HStack{
                    Spacer()
                    Text("Login")
                    Spacer()
                }
                .accentColor(Color.white)
                .padding(.vertical, 10)
                .background(Color.red)
                .cornerRadius(5)
                .padding(.horizontal, 40)

            }

        }.padding()}

       }
      }

      struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
       }

and in userdetails this so I need to get values from response

struct userdetails: View {

  @State var controller = getres()
    var body : some View{
        ScrollView(Axis.Set.vertical, showsIndicators: true) {

            VStack(spacing: 20){
            Image("wlogo").renderingMode(.original);              HStack(spacing: 15){

                  Spacer()
                  VStack(alignment: .center, spacing: 10) {

                    Text(???).foregroundColor(Color.white).bold()
                        .font(.largeTitle)

                    Text("")
                    .foregroundColor(Color.white)
                        .font(.headline)                  }

                  Spacer()
              }}}}

how can I get ordercount from response and put in text(???) in the view userdetails for example controller.todos.ordercount I get this error Value of type '[result]' has no member 'ordercount' when I try Text(controller.todos.ordercount) json response

{"res":"2","ordercount":"20","rate":"5"}

Upvotes: 0

Views: 2055

Answers (1)

Chris
Chris

Reputation: 8091

UPDATED ANSWER

1.) it would be helpful if you copy your code in just one part - this is easier for all of us to copy 2.) you should try out your code yourself before you copy or change something in your code manually. it is annoying to find mistakes like:

if manager.authenticated == "2"{ userdetails() } else{

        Text("Username")
        TextField("placeholder", text: $username)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .border(Color.green)
            .autocapitalization(.none)

        Text("Password")
        SecureField("placeholder", text: $password)
            .textFieldStyle(RoundedBorderTextFieldStyle())
            .border(Color.green)

        Button(action: {

            self.manager.auth(username: self.username, password: self.password)

        }) {
            HStack{
                Spacer()
                Text("Login")
                Spacer()
            }
            .accentColor(Color.white)
            .padding(.vertical, 10)
            .background(Color.red)
            .cornerRadius(5)
            .padding(.horizontal, 40)

        }

    }.padding()}

}

where you are adding .padding() to an if-statement....

3.) you should name class names in that way people can understand what the class if for and start with a capitalized letter like Apple does with all class names

4.) you should also begin View names capitalized (like Apple does) 5.) since i have to access to your page and you did not provide example data and/or password i have no idea what data are coming there...

here is my solution code so far:

i added some faking data, because i cannot access your data ....so you can see something in details.

struct ToDo: Decodable, Identifiable {

    var id = UUID().uuidString

    let res, ordercount, rate: String
}

class ToDoGetter: ObservableObject {

    let objectWillChange = PassthroughSubject<ToDoGetter, Never>()
    @Published var authenticated = ""
    @Published var todos = [ToDo]() {
        didSet {
            objectWillChange.send(self)
        }
    }

    let someFakingTodos = [
        ToDo(res: "a", ordercount: "5", rate: "75%"),
        ToDo(res: "b", ordercount: "52", rate: "5%"),
        ToDo(res: "c", ordercount: "566", rate: "7%"),
        ToDo(res: "d", ordercount: "53", rate: "33%"),
        ToDo(res: "e", ordercount: "15", rate: "44%"),
        ToDo(res: "f", ordercount: "345", rate: "10%")

    ]

    func auth(username: String, password: String) {
        guard let url = URL(string: "http://company.com/auth.php") else { return }

        let body: [String: String] = ["username": username, "password": password]

        let finalBody = try! JSONSerialization.data(withJSONObject: body)

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = finalBody
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        URLSession.shared.dataTask(with: request) { (data, response, error) in


            guard let data=data else{return}

            let fineldata=try! JSONDecoder().decode(ToDo.self, from: data)

            DispatchQueue.main.async {
                self.todos = [fineldata]
                self.authenticated=fineldata.res
            }
            print(fineldata)
        }.resume()
    }
}

struct ContentView: View {

    @EnvironmentObject var todoGetter : ToDoGetter

    @State private var username: String = ""
    @State private var password: String = ""


    @State var navigateToDetail : Bool = false

    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {

                if todoGetter.authenticated == "2"{
                    Userdetails().environmentObject(todoGetter)
                } else{

                    Text("Username")
                    TextField("placeholder", text: $username)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .border(Color.green)
                        .autocapitalization(.none)

                    Text("Password")
                    SecureField("placeholder", text: $password)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .border(Color.green)

                    NavigationLink(destination: Userdetails(), isActive: self.$navigateToDetail) {
                        EmptyView() }
                        .hidden()
                        .padding()

                    Button(action: {

                        self.todoGetter.auth(username: self.username, password: self.password)
                        self.navigateToDetail.toggle()
                    }) {
                        HStack{
                            Spacer()
                            Text("Login")
                            Spacer()
                        }
                        .accentColor(Color.white)
                        .padding(.vertical, 10)
                        .background(Color.red)
                        .cornerRadius(5)
                        .padding(.horizontal, 40)
                    }
                }
            }
        }
    }
}

struct Userdetails: View {

    @EnvironmentObject var todoGetter : ToDoGetter

    var body : some View{

        VStack(spacing: 20) {
            Image("wlogo").renderingMode(.original);              HStack(spacing: 15){

                Spacer()

                List(todoGetter.someFakingTodos) { todo in

                    VStack(alignment: .center, spacing: 10) {
                        HStack {
                            Text(todo.res).foregroundColor(Color.white).bold()
                                .font(.largeTitle)

                            Text(todo.ordercount)
                                .foregroundColor(Color.white)
                                .font(.headline)
                            Text(todo.rate)
                                .foregroundColor(Color.white)
                                .font(.headline)
                        }
                    }.background(Color.black)

                    Spacer()
                }
            }
        }
    }
}

OLD ANSWER

you call getres 2 times. you have to call it just once and then give the value to the detailview.

the model should only be created once per app.

Upvotes: 1

Related Questions