I am working with a Picker that is getting its values from an array of Categories (it's own @Model, no issue there) and needs to save the selected item to a variable in Product.category in another @Model. My list does not allow me to select an item so I am thinking I may have an issue with the binding but cannot see where the issue is.
Any thoughts/guidance would be much appreciated! And if anyone can suggest how i can edit the Product.name var from this View, that would be much appreciated too :)
My code is as follows:
ProductView.swift
import SwiftData
import SwiftUI
struct ProductView: View {
@Environment(\.modelContext) private var modelContext
@Environment(\.dismiss) private var dismiss
@Query(sort: \Category.name) var categories: [Category]
// let product: Product
@Bindable var product: Product
@State private var formType: ProductFormType?
@State private var showVendors = false
@State private var showCategories = false
var body: some View {
List {
Section(header: Text("Product Image")) {
VStack {
// MARK: Ternary to add image if there is not one to display and Edit button if there is one
if let image = product.image {
Image(uiImage: image)
.resizable()
.scaledToFit()
.cornerRadius(12)
.clipped()
.padding()
} else {
Text("Add a photo")
// Image(systemName: "photo")
// .foregroundColor(.secondary)
// .opacity(0.2)
// .font(.system(size: 160))
// .frame(width: 250, height: 250)
}
Button("Edit Photo") {
formType = .update(product)
}
}
}
Section(header: Text("Where I can buy this Product")) {
Button("Add or Create Vendor(s)", systemImage: "house.fill") {
showVendors.toggle()
}
// MARK: Need to find a way to color only SF Symbol
// .foregroundColor(.gray)
.sheet(isPresented: $showVendors) {
VendorsView(product: product)
}
if let vendors = product.vendors {
ViewThatFits {
VendorsGridView(vendors: vendors)
ScrollView(.horizontal, showsIndicators: false) {
VendorsGridView(vendors: vendors)
}
}
}
}
Section(header: Text("Product Category")) {
Button("Add or Create Category(ies)", systemImage: "house.fill") {
showCategories.toggle()
}
// MARK: Need to color only SF Symbol
// .foregroundColor(.gray)
.sheet(isPresented: $showCategories) {
CategoriesView(product: product)
}
Picker("Please select a Category", selection: $product.category) {
ForEach(categories) { category in
Text(category.name).tag(category as Category)
// Text(category.name)
}
}
.pickerStyle(.wheel)
if let categories = product.categories {
ViewThatFits {
CategoriesGridView(categories: categories)
ScrollView(.horizontal, showsIndicators: false) {
CategoriesGridView(categories: categories)
}
}
}
// Text("You selected: \(product.category ?? ""))
}
Spacer()
HStack {
// MARK: Need to add deletion confirmation dialogue
Button("Delete Product", role: .destructive) {
modelContext.delete(product)
try? modelContext.save()
dismiss()
}
}
.buttonStyle(.borderedProminent)
.frame(maxWidth: .infinity, alignment: .trailing)
}
.sheet(item: $formType) { $0 }
.navigationTitle(product.name)
.navigationBarTitleDisplayMode(.inline)
// MARK: Need to find a way to make Product name editable on this view
.toolbarRole(.editor)
}
}
Models
import SwiftData
import UIKit
@Model
class Product {
var name: String = ""
@Attribute(.externalStorage)
var data: Data?
@Relationship(inverse: \Vendor.products)
var vendors: [Vendor]?
var category: String? = ""
var image: UIImage? {
if let data {
return UIImage(data: data)
} else {
return nil
}
}
init(name: String, data: Data? = nil, category: String) {
self.name = name
self.category = category
self.data = data
}
}
@Model
class Category {
var name: String = ""
var products: [Product]?
init(
name: String
) {
self.name = name
}
}