Home > Enterprise >  Swiftui Navigation link not updating correctly with each individual user's page in a gridview
Swiftui Navigation link not updating correctly with each individual user's page in a gridview

Time:03-21

I am trying to achieve a view with users in a Vgrid, when a user's profile picture is tapped it should go directly to his/her profile. I have tried a lot of ways to make it work any help is needed.

When i tap on any user it goes to the first user in my firebase collections and does not navigate to the user's profile i tapped.

The PeepsGridView() in the VGrid works correctly and user searches and matched correcly it just the issue with the correct profile for each user tapped.

Below is the View with the Vgrid and the Navigation link to the profile view:

struct PeopleView: View {
    @ObservedObject var peoplesViewModel = PeopleViewModel()
    @EnvironmentObject var profileviewModel: ProfileViewModel
    private let items = [GridItem(), GridItem(), GridItem()]
    
    var body: some View {
        NavigationView {
                VStack(spacing: 0) {
                    PeopleTopView()
                        .padding(.top, 45)
                    
                    PeopleSearchBarView(text: $peoplesViewModel.searchText)
                        .padding()
                        
                   ScrollView(.vertical, showsIndicators: false) {
                       
                                NavigationLink {
                                    ScrollView(.vertical, showsIndicators: false) {
                                        ForEach(self.peoplesViewModel.users) { susers in
                                            VStack {
                                              ProfileInfoView(user: susers)
                                            }
                                        }
                                    }
                                } label: {
                                    LazyVGrid(columns: items, spacing: 2) {
                                        ForEach(peoplesViewModel.searchableUsers) { peep in
                                    PeepsGridView(userInfo: peep)
                                                
                                            
                                        }
                                    }
                                }
                  } //End ScrollView
                }
                .navigationBarTitle("")
                .navigationBarHidden(true)
                .ignoresSafeArea(.all, edges: .top)
        } //End NavigationView
    }
}

I am getting my users from Firebase so i will include the 2 view models i linked:

import Foundation

class PeopleViewModel: ObservableObject {
    @Published var users = [User]()
    @Published var searchText = ""
    
    var searchableUsers: [User] {
        if searchText.isEmpty {
           return users
        } else {
            let lowercasedQuery = searchText.lowercased()
            
            return users.filter ({
                $0.username.contains(lowercasedQuery) ||
                $0.fullname.lowercased().contains(lowercasedQuery)
            })
        }
    }
     
    
    let service = UserService()
    
    init() {
        fetchUsers()
    }
    
    func fetchUsers() {
        service.fetchUsers { users in
            self.users = users
        }
    }
}

This is the second view model:

import Foundation

class ProfileViewModel: ObservableObject {
    @Published var feedtry = [FeedTry]()
    @Published var likedTry = [FeedTry]()
    private let service = UploadTryService()
    private let userService = UserService()
    var user: User
    
    
    init (user: User) {
        self.user = user
        self.fetchUserFeedTry()
        self.fetchLikedTry()
    }
    
    var actionButtonTitle: String {
        return user.isCurrentUser ? "Edit Profile" : "Follow"
    }
    

    
    func feedtrys(forFilter filter: ProfileFilterViewModel) -> [FeedTry] {
        switch filter {
        case .music:
            return feedtry
        case .pictures:
            return feedtry
        case .videos:
            return likedTry
        }
    }
    
    
    func fetchUserFeedTry() {
        guard let uid = user.id else { return }
        service.fetchTry(forUid: uid) { feedtrys in
            self.feedtry = feedtrys
            
            for i in 0 ..< feedtrys.count {
                self.feedtry[i].user = self.user
            }
        }
    }
    
    func fetchLikedTry() {
        guard let uid = user.id else { return }
        
        service.fetchLikedTry(forUid: uid) { feedtry in
            self.likedTry = feedtry
            
            for i in 0 ..< feedtry.count {
                let uid = feedtry[i].uid
                
                self.userService.fetchUser(withUid: uid) { user in
                    self.likedTry[i].user = user
                }
            }
        }
    }
    
    
}

And lastly this is the code i have above the body of my profile view:

import SwiftUI
import SDWebImageSwiftUI

struct ProfileView: View {
    @ObservedObject var profileviewModel: ProfileViewModel
    @Namespace var animation
    
    
    init(user: User) {
        self.profileviewModel = ProfileViewModel(user: user)
    }
    
}

CodePudding user response:

You can't have one NavigationLink that has all possibilities inside of it. Instead, you create all of your possibilities and then put a NavigationLink around each possibility. The other issue with your code is you are using two different sets of data, one as the data model for the NavigationLink, and the other as the data model for the label. These have to be the same, or else things are hopelessly confused. Further, if you do not always have an identical amount of susers and peep, you will have a crash when one runs out before the other. Since you wanted to navigate using susers, I used that variable in the code below:

ScrollView(.vertical, showsIndicators: false) {
    LazyVGrid(columns: items, spacing: 2) {
        ForEach(self.peoplesViewModel.users) { susers in           
            NavigationLink {
                ProfileInfoView(user: susers)
            } label: {
                PeepsGridView(userInfo: users)
            }
        }
    }
} //End ScrollView
  • Related