I'm working on a SwiftUI app where I have a Todo model and a TodoView to display a list of todos. The todos are stored using SwiftData, and I'm using a @Query property to fetch and display them in a List. However, when I add a new todo using a button, the new item doesn't appear in the list, even though the note variable contains the correct value.
import SwiftUI
import SwiftData
@main
struct mmApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Todo.self)
}
}
import SwiftUI
import SwiftData
struct todo: View {
@Query private var todos: [Todo]
@Environment(\.modelContext) private var context
@State private var note = ""
var body: some View {
ZStack {
VStack {
NavigationStack {
List(todos, id: \.self) { todo in
HStack {
Text("Hello")
.swipeActions {
Button("Delete", role: .destructive) {
context.delete(todo)
}
}
}
}
.safeAreaInset(edge: .bottom) {
VStack(alignment: .center, spacing: 20) {
Text("New ToDo")
.font(.headline)
HStack {
TextField("Todo", text: $note)
.padding()
.background(Color.white)
.cornerRadius(8)
.shadow(radius: 8)
.frame(width: 300)
Button(action: {
let newNote = Todo(note: note)
context.insert(newNote)
print(newNote.id, newNote.note)
note = ""
}) {
Label("Add", systemImage: "plus")
.foregroundStyle(.white)
.font(.subheadline)
.bold(true)
}
.frame(width: 60, height: 44)
.background(Color.green)
.cornerRadius(10)
}
}
.padding()
.background(.bar)
}
}
}
}
}
}
#Preview {
todo()
}
swift
import Foundation
import SwiftData
@Model
class Todo {
var id: UUID
var note: String
init(note: String) {
self.id = UUID()
self.note = note
}
}
You need to provide a model container to the Preview
:
#Preview {
ToDoView()
.modelContainer(for: ToDo.self)
}
But your code has many other issues, beginning with not respecting Swift naming conventions (like having a struct named todo
), and using deprecated modifiers like .cornerRadius
.
There's also no need for all the forced frame values for the button and text field to achieve a proper layout.
Here's the code with some adjustments:
import SwiftUI
import SwiftData
//Main App
@main
struct ToDoApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
ToDo.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ToDoView()
}
.modelContainer(sharedModelContainer)
}
}
//Root view
struct ToDoView: View {
@Query private var toDos: [ToDo]
@Environment(\.modelContext) private var context
@State private var note = ""
var body: some View {
ZStack {
VStack {
NavigationStack {
List(toDos, id: \.self) { toDo in
HStack {
Text(toDo.note)
.swipeActions {
Button("Delete", role: .destructive) {
context.delete(toDo)
}
}
}
}
.safeAreaInset(edge: .bottom) {
VStack(alignment: .center, spacing: 20) {
Text("New To Do")
.font(.headline)
HStack(spacing: 12) {
TextField("To do: ...", text: $note)
.padding()
.background(Color.white, in: RoundedRectangle(cornerRadius: 8))
.shadow(radius: 8)
// .frame(width: 300)
Button(action: {
let newNote = ToDo(note: note)
context.insert(newNote)
print(newNote.id, newNote.note)
note = ""
}) {
Label("Add", systemImage: "plus")
.foregroundStyle(.white)
.font(.subheadline)
.bold(true)
.padding()
}
.fixedSize()
.background(Color.green, in: RoundedRectangle(cornerRadius: 10))
}
}
.padding()
.background(.bar)
}
}
}
}
}
}
#Preview {
ToDoView()
.modelContainer(for: ToDo.self)
}
@Model
class ToDo {
var id: UUID
var note: String
init(note: String) {
self.id = UUID()
self.note = note
}
}