Passing data through NavigationLink - not working

Hello community,

I have some trouble with this code:
What I want is passing different data by the custom views I made. Each button should show different Lists with JSON data.

When I click the “laundry” button it should go to a custom view that I made which should be a presented view. But it’s asking me for a parameter, what is it I should put in? Maybe Im doing something wrong?

I’ve tried doing som research but didn’t get any smarter. I was hoping anyone here could help.

struct FetchData {

func getLocalData() -> [Laundry] {
    
    //        We need to get the path to the "LaundryData"
    if let url = Bundle.main.url(forResource: "LaundtryData", withExtension: "json") {
        
        do {
            //        Read the file and turn it into data
            let data = try Data(contentsOf: url)
            
            //        Parse data into Swift instances
            let decoder = JSONDecoder()
            
            do {
                let laundryData = try decoder.decode([Laundry].self, from: data)
                return laundryData
            } catch {
                print("Couldn.t parse the JSON file: \(error)")
            }
           

        } catch {
            
            print("Couldn.t read the file: \(error)")
            
        }
        
        
        
    }
    
    return [Laundry]()
}

}

struct Laundry: Identifiable, Codable{

let id = UUID()
var image: String
var description: String
var summary: String
var tumbling: [Tumbling]

}

struct LaundryList: View {

var laundry: Laundry

var body: some View {
    

        VStack {
            
            List {
                
                WashListRow(laundry: laundry)
                
            }
            


                
            
        }
    
    
}

}

#Preview {
LaundryList(laundry: Laundry(image: “wash60”, description: “dummy data”, summary: “mock data”, tumbling: [Tumbling(image: “lowDrying”, description: “mock data”, summary: “summary data”)]))
}

struct WashListRow: View {

var laundry: Laundry

var body: some View {
    
    
    HStack(spacing: 30) {
        
        Image(laundry.image)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 35, height: 35)
            
        
        Text(laundry.description)
            .font(.callout)

    }
        
    
    
}

}

#Preview {
WashListRow(laundry: Laundry(image: “wash60”, description: “Normal Wash at 60°”, summary: “more dummy data”, tumbling: [Tumbling(image: “wash60”, description: “test”, summary: “more dummy data”)]))
}

struct MainView: View {

@State var clean = [Laundry]()
var dataService = FetchData()


var body: some View {
    
    NavigationStack {
        
        VStack(spacing: 30) {
            
            
            
            Text("Take care of your wash")
                .font(.title2)
                .padding(.top, 40)
            
            Spacer()
            
            NavigationLink {
                
                ForEach(clean) { item in
                    
                    List(item) { _ in
                        
                        LaundryList(laundry: item)
                        
                    }
                    
                }
                
            } label: {
                LaundryView()
            }

            
            
            
            
            TumbleView()
            
            
            Spacer()
            
            
        }.onAppear(perform: {
            clean = dataService.getLocalData()
        })
    }
}

}

#Preview {
MainView()
}

sorry for the very long post

/Nicholas

What specifically is the problem you are having? Is your project not building? Are you getting unexpected behavior when you click the Laundry button?

When I click the “laundry” button it should go to a custom view that I made which should be a presented view. But it’s asking me for a parameter, what is it I should put in?

Can you clarify what you mean by “it’s asking me for a parameter”? Is your app asking for a parameter when you click the Laundry button? Or is Xcode asking you to add a parameter somewhere in your code?

I see a potential problem in your code to read the JSON file from the app bundle. You have a possible misspelling of the name of your data file in your code.

if let url = Bundle.main.url(forResource: "LaundtryData", withExtension: "json")

Is your file named LaundtryData or LaundryData? If your file is named LaundryData, the getLocalData function is going to return an empty array. With an empty array your laundry list is going to be empty.

I simply don’t know what data to pass in the parameter it’s asking me for showing the “LaundryList” view that I made. When I click on the LaundryView() it should move to the other view which is the LaundryList()

The JSON is working, I did some breakpoints to check if it returns an empty array and it doesn’t.

Maybe if I attach picture with the block of code it makes it a little easier?

in a simple way, I want to move from one screen to another.

i have tried so many ways to pass the data from the MainView to the LaundryList(laundry: ___), that Im just more confused now.


if more information is needed just say and I provide.

/Nicho

Your main view has an array of Laundry items.

@State var clean = [Laundry]()

And your laundry list view has a single Laundry item.

var laundry: Laundry

Why do you have a list with only one item? Shouldn’t you have an array of Laundry items in the laundry list?

If you create a binding for the array of Laundry items in the laundry list view,

@Binding var laundryItems: [Laundry]

You can pass the clean variable from the main view to the laundry list view in the navigation link.

NavigationLink {
  LaundryList(laundryItems: $clean)
} label: {
  LaundryView()
}

In the list you create in LaundryList, add an instance of WashListRow for each item in the array. The code will look similar to the following:

List(laundryItems) { item in
  WashListRow(laundry: item)
}

You might have to place a ForEach block inside the list and use that to add the wash list rows.

After some testing it kinda works, it works for the example that you showed me,

I want to do the same thing for another custom view, the difference is it should show the “tumble” data but the data does not get passed. Its saying “Cannot convert value of type ‘[Laundry]’ to expected argument type ‘[Tumbling]’” even though my Laundry struct has a tumbling property.

By tapping the blue custom rectangle with the text Laundry it shows me a list with the correct JSON data. Now I want to do the same thing for the other custom View. the cyan coloured Rectangle with the text Tumble Drying. BUT embedding the custom view in a NavigationLink does not work. Any other ideas? anything would be helpful.

I will link the code, maybe that helps.

The link for the GitHub gist is:This is the link

The tumbling list takes an array of Tumbling objects.

var tumbling: [Tumbling]

In your main view, you have the clean property, which is an array of Laundry objects.

@State var clean = [Laundry]()

You are trying to pass an array of Laundry to a view that takes an array of Tumbling in your navigation link.

NavigationLink {
  TumblingList(tumbling: clean) -> not working
    } label: {
    TumbleView()
  }

You need to pass an array of Tumbling to the tumbling list. The Laundry struct has a tumbling property. That’s what you need to pass to the tumbling list.

First, make tumbling a binding in the tumbling list. You need a binding to pass the tumbling from the main view to the tumbling list.

@Binding var tumbling: [Tumbling]

Second, you have to pass the tumbling array from one of the laundry items from the clean array to the tumbling list in the navigation link. The code will look similar to the following:

NavigationLink {
  TumblingList(tumbling: laundryItem.tumbling)
 } label: {
    TumbleView()
 }

You are going to have to come up with a way to get one of the laundry items from the clean array. What would work better to get to the tumbling list is to select an item from the laundry list and pass the selected laundry item’s tumblings to the tumbling list instead of passing the tumblings from the main view.

1 Like