2

Elaborating the Problem in depth with code

I have a data model (API response) using which I am creating a list. The list items should also display their details in detail view. The problem is details of list items are coming from a different API other than the API used for creating the list. The id of one item is passed to API which in response provides the details of the item.

This is the data model(including items only problem specific):

struct TrackSample : Codable, Identifiable {
    let id = UUID()
    let success : Bool
    let message : String
    let trackResponse : [TrackResponse]

    enum CodingKeys: String, CodingKey{
    case success = "IsSuccess"
    case message = "Message"
    case trackResponse = "ResponseData"
    }}

struct TrackResponse : Codable, Identifiable {
    let id = UUID()
    let patientID : String
    let name : String
    let testCount : Int
//..some more//

enum CodingKeys: String, CodingKey {
    case patientID = "PatientId"
    case name = "Name"
    case status = "Status"
case testCount = "NoOfTests"
    }}

ViewModel to fetch API response ( TrackResource() is a different class which implements the networking call):

class TrackViewModel : ObservableObject
    {
        @Published var trackReport = [TrackResponse]()
        @Published var navigate:Bool = false
        //other var
        private let trackResource = TrackResource()

    func getTrack()
    {
    //code to get data based on which button is clicked in Options 
    screen. 
    There are five options to choose:
    if else statement follows//
        
    centerID = "100"
    
        let trackRequest = TrackRequest(CenterId:centerID, 
    SearchText:searchText, StartDate:startDate, EndDate:endDate)
     trackResource.track(trackRequest: trackRequest)
        {
         response in
         if(response?.success==true)
          {
                DispatchQueue.main.async {
                self.navigate = true
                self.trackReport = response?.trackResponse ?? []
            }
        }
        else
        {
            DispatchQueue.main.async {
                self.errorMessage = response?.message ?? "No Data"
             //   self.isPresentingAlert
            }
        }}}}

The view YdaySample which represents the list :

struct YdaySample: View {

@ObservedObject var tracking : TrackViewModel

    var body: some View {

    NavigationView{

        List{
         ForEach(tracking.trackReport)
            { truck in
             NavigationLink(destination: TrackDetail(track:truck))
                        {
                            YdayRow(truck: truck)
                        }
                }
         if(tracking.trackReport.isEmpty){
        Text("No Record Found !")
            //formatting
        }}}}}

struct YdaySample_Previews: PreviewProvider {
static var previews: some View {
 YdaySample(tracking: TrackViewModel())
         }}

The YdayRow() :

      struct YdayRow: View {
     var truck : TrackResponse
     var body: some View {
     VStack{
         HStack{
                Text(truck.name)
            //formatting//
        }
    HStack{
            Text("P.Id:")
            //formatting//
            Text(truck.patientID)
            //formatting//
    
        Spacer()
        Text("Total Test:")
            //formatting//
        Text("\(truck.testCount)")
            //formatting//
    }}}}

  struct YdayRow_Previews: PreviewProvider {
         static var previews: some View {
        YdayRow(truck: TrackResponse(patientID: "1", name: "test", 
  status: "null", crmNo: "null", 
      recordDate: "somedate", uniqueID: "null", testCount: 4))
        }
    }

TrackDetail() updated:

 struct TrackDetail: View {

 var track: TrackResponse
 @State var patientDetail: DetailResponse
 
 var body: some View {
        VStack{
            HStack{
                Text(track.name)
                   //formatting
                    }.frame(maxWidth: .infinity, alignment: .center)
            
                HStack{
                Text("P.Id:")
                        //formatting
                    Text(track.patientId)
                       //formatting
               
               }
           
                List{ForEach(patientDetail.detailResponse)
                        {detail in
                            HStack
                        { Text("Barcode: ")
                            Text(detail.barcode)
                        }
                    }
                }.onAppear{
                    Task{
                        do{
                            try await getDetail()
                        }catch{
                Alert(title: Text("Error"),message: Text("Not Found"), 
            dismissButton: .cancel())
                        }}}}}

func getDetail() async throws{
    
  
    var urlComponents = URLComponents()
    urlComponents.scheme = "http"
    urlComponents.host = "xx.xxx.xx.xx"
    urlComponents.path = "/api/reports/getalltests"
    urlComponents.queryItems = [URLQueryItem(name: "centerId", value: 
    ("\(668)")),URLQueryItem(name: "patientId", value: "\ 
    (track.patientId)")]

    let url = urlComponents.url

    var request = URLRequest(url: url!)
    print(request)
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    request.setValue("application/json", forHTTPHeaderField: "Content- 
    Type")
    request.setValue("Basic xcvgjhalddjdj",forHTTPHeaderField: 
    "Authorization")
    // Send HTTP Request
    let task = URLSession.shared.dataTask(with: request) { (data, 
     response, error) in
        
        // Check if Error took place
        if let error = error {
            print("Error took place \(error)")
            return
        }
        
        // Read HTTP Response Status code
        if let response = response as? HTTPURLResponse {
            print("Response HTTP Status code: \(response.statusCode)")
        }
        
       if let data = data
        
        {
           
              let dataString = String(data:data,encoding: .utf8)
              print(dataString!)
            
             do{
                let json = try JSONDecoder().decode(DetailResponse.self, 
               from: data)
               print(json)
                DispatchQueue.main.async {
                    self.patientDetail = json
                }
             
    
            }catch{
                print("error \(error)")
            }
                      
        }
    };task.resume()
        }}



    struct TrackDetail_Previews: PreviewProvider {
    static var previews: some View {
    TrackDetail(track: TrackResponse(patientId: "4193716", name: "Dummy 
    Report HCV RNA", status: "null", crmNo: "null", recordDate: "2022- 
     04-15", uniqueId: "null", testCount: 10), patientDetail: 
     DetailResponse(success: false, message: "mess", detailResponse: 
       []))
    }}

print(request) is printing right URL as desired also the patientID is correct in url (http://xxx..x.x/api/reports/getalltests/centerId=668&patientId=(tapped id))

But it is throwing error in decoding saying "Authrization has been denied for this request" error keynotfound(codingkeys(stringvalue: "ResponseData", intvalue:nil), Swift.decodingerror.context(codingpath: [],debugdescription: "No value associated with key CodingKeys(stringvalue: "ResponseData", intvalue:nil)("ResponseData", underlyingError:nil)

struct DetailResponse : Codable{
    let success : Bool ?
    let message : String
    let detailResponse : [PatResponse]

    enum CodingKeys: String, CodingKey{
    case success = "IsSuccess"
    case message = "Message"
    case patResponse = "ResponseData"
    }}

struct PatResponse : Codable, Identifiable {    
    var barcode: String
    var:id String {barcode} 
    let testname : String?
    let packageName : String?
    let status: String?
    let sampleRecievedTime: String?
    let recordDate: String

enum CodingKeys: String, CodingKey {
    case packageName = "PackageName"
    case testname = "TestName"
    case status = "Status"
    case sampleRecievedTime = "SampleRecievedTime"
    case recordDate = "RecordDate"
    case barcode = "Barcode"
    }}

///////**************/////////////////// The detail view is showing name and ID as they are coming from TrackResponse but status and barcode are not as they are from different API.

When the user click/tap an item in list, the patientID and centerId is sent as query param in GET request which in response will provide the details associated with the given patientId (center ID is constant). How to implement this?

tintin
  • 335
  • 2
  • 8
  • You don´t need a viewmodel for this you could implement your `getDetail` func directly in your `TrackDetail` View. Your patient id should be `track.PatientId` and make the `detailPatient` var a `@State` and optional like in my answer. Please comment what you don´t understand or having struggle with implementing. – burnsi Apr 23 '22 at 17:50
  • 1
    @burnsi I tried in the evening but failed to implement as I tried to use viewmodel to implement your soln which became total mess...now I will try again without viewmodel will define func directly in struct as you described and revert back as soon as possible – tintin Apr 23 '22 at 18:00
  • @burnsi its not working...can you provide the sample code....after creating func have to change the code everywhere as it is saying argument missing or maybe I am implementing it wrongly – tintin Apr 24 '22 at 13:42

1 Answers1

1

How about something like this?

struct TrackDetail: View{
    
    var track: TrackResponse
    @State var details: TrackDetails?
    
    var body: some View{
        HStack{
            //Detail implementation
        }.onAppear{
            Task{
                do{
                    try await doStuff()
                }catch{
                    //Alert
                }
            }
        }
    }
    
    func doStuff() async throws{
        // pull Details from Api
        
    }
}
burnsi
  • 6,194
  • 13
  • 17
  • 27
  • its not working blank as before ....can you provide sample code – tintin Apr 24 '22 at 10:33
  • @tintin please update your question so i can see what you have done so far. The answer i provided is as detailed as i can get without knowing more about code. – burnsi Apr 25 '22 at 09:08
  • i have updated the Q pls look @burnsi – tintin Apr 25 '22 at 10:07
  • @tintin `Authrization has been denied for this request` seems like your request itself fails. You probably need some kind of login sequence to get that data. But i deem this out of the scope of this question. Please investigate further (perhaps googeling or asking another question) and come back as soon as you have solved it. – burnsi Apr 25 '22 at 10:41
  • 1
    Hi @burnsi, resolved all values are retrieved successfully....there was one issue ----url.port I was not mentioning it explicitly i mentioned it and it worked (can it be a reason?)...thanks for your help really appreciate it i was stuck with this for 3 days nowhere to go your code directed in right way....finally resolved – tintin Apr 26 '22 at 05:27