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