Reputation: 3
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
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