luck99
luck99

Reputation: 51

SwiftUI how get Firebase data from @ObservedObject ViewModel without using List

I am learning SwiftUI and I am trying to retrieve information after retrieving data from my database with Firebase.

I retrieve the data once to display it in a summary way then with a Link Navigation I try to retrieve the rest of the information for a more accurate display but I have an error. I want to retrieve accurate data without using List.

PrintSpecificData.swift

//
//  complete_deliv_view.swift
//  db_test
//
//  Created by admin on 21/03/2021.
//

import SwiftUI

struct complete_deliv_view: View {
    @ObservedObject private var viewModel = delivViewModel()
    var body: some View {
        Text(self.viewModel.av_deliveries.from) // ERROR IS HERE
        .onAppear() {
            self.viewModel.fetchDelivResume()
        }
    }
}

struct complete_deliv_view_Previews: PreviewProvider {
    static var previews: some View {
        complete_deliv_view()
    }
}

Print summary data

//
//  ContentView.swift
//  db_test
//
//  Created by admin on 21/03/2021.
//

import SwiftUI

struct delivResum:Identifiable {
    // SUMMARY INFORMATIONS
    var id: String = UUID().uuidString
    var when: String
    var from: Int
    var to: Int
    var whath: Int
    // FULL INFORMATIONS
    var name: String
    var adress: String
    var to_adress: String
    var tel: Int
}

struct ContentView: View {
    @ObservedObject private var viewModel = delivViewModel()
    var body: some View {
        NavigationView {
            NavigationLink(destination:complete_deliv_view()) {
                List(viewModel.av_deliveries) { deliv in
                    HStack {
                        Text ("🚨")
                        Text(deliv.when)
                        Text ("🏠")
                        Text(String(deliv.from))
                        Text ("➡")
                        Text(String(deliv.to))
                        Text ("⏰")
                        Text("\(deliv.whath)h")
                    }
                }
                .navigationBarTitle("Livraisons")
                .onAppear() {
                    self.viewModel.fetchDelivResume()
                }
            }
        }
        
    }
}

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

FetchDataFromFirebase.swift

//
//  delivViewModel.swift
//  db_test
//
//  Created by admin on 21/03/2021.
//

import Foundation
import FirebaseFirestore

class delivViewModel : ObservableObject {
    @Published var av_deliveries = [delivResum]()
    
    private var db = Firestore.firestore()
    
    func fetchDelivResume() {
        db.collection("av_deliveries").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("Pas de livraison disponible 😩")
                return
            }
            self.av_deliveries = documents.map { (QueryDocumentSnapshot) -> delivResum in
                let data = QueryDocumentSnapshot.data()

                let when = data["when"] as? String ?? ""
                let from = data["from"] as? Int ?? 0
                let to = data["to"] as? Int ?? 0
                let whath = data["whath"] as? Int ?? 0
                let name = data["name"] as? String ?? ""
                let adress = data["adress"] as? String ?? ""
                let to_adress = data["to_adress"] as? String ?? ""
                let tel = data["tel"] as? Int ?? 0
                
                return delivResum(when: when, from: from, to: to, whath: whath, name: name, adress: adress, to_adress: to_adress, tel: tel)
            }
        }
    }
}

This may be a silly question but I don't really understand how to get only the phone number for example in the PrintSpecificData.swift

Thank you for your precious help

Upvotes: 0

Views: 241

Answers (1)

jnpdx
jnpdx

Reputation: 52397

Instead of recreating your view model on the detail view, you can instead pass just a single instance of delivResnum as a parameter. You'll have to change the structure of your ContentView slightly so that it has a different NavigationLink for each row, rather than wrapping the entire list.


struct ContentView: View {
    @ObservedObject private var viewModel = delivViewModel()
    var body: some View {
        NavigationView {
            List(viewModel.av_deliveries) { deliv in
                NavigationLink(destination:complete_deliv_view(deliv: deliv)) {
                    HStack {
                        Text ("🚨")
                        Text(deliv.when)
                        Text ("🏠")
                        Text(String(deliv.from))
                        Text ("➡")
                        Text(String(deliv.to))
                        Text ("⏰")
                        Text("\(deliv.whath)h")
                    }
                }
            }
            .navigationBarTitle("Livraisons")
            .onAppear() {
                self.viewModel.fetchDelivResume()
            }
        }
    }
}

struct complete_deliv_view: View {
    var deliv : delivResum
    var body: some View {
        Text(deliv.from)
    }
}


Note: in Swift, it's common practice to capitalize type names. You'd want to rename to DelivResum and DelivViewModel if you were to follow this convention.

Upvotes: 1

Related Questions