swiftuiswiftdatalazyvstack

Update on Parent View list from Child view using SwiftData


My problem is with SwiftData not updating the object which is used with @Query. here are my code This is my View which used to show list of books,

struct ReadingView: View {
    
@Environment(\.modelContext) private var modelContext
@Query(filter: #Predicate<SDBook> { book in
    book.status == "reading"
}) var itemsBooks: [SDBook]

@Query var items: [SDBook]


var body: some View {
    ScrollView {
        LazyVStack {
            ForEach(itemsBooks, id: \.id) { value in
                ReadingRowView(book: value)
            }
        }
    }
    
    
}

}

and from ReadingRowView, i am presenting alert to update the current page in book, but this change is not updating in ReadingView().

Here is the code for ReadingRowView

@Observable
class ReadingBooksModel {
var book: SDBook

  init(book: SDBook) {
    self.book = book
  }
}
struct ReadingRowView: View {
 @Environment(\.modelContext) private var modelContext
 private var itemModel: ReadingBooksModel
 @State var progress = 0.0
 @State private var showingAlert = false
 @State private var pageRead = ""
 @State private var showError = false

 init(book: SDBook) {
     self.itemModel = ReadingBooksModel(book: book)
 }

 var body: some View {
    HStack {
        if let selectedPhotoData = itemModel.book.image, let uiImage = UIImage(data: selectedPhotoData) {
            Image(uiImage: uiImage)
                .resizable()
                //.frame(minWidth: 0, maxWidth: .infinity)
                .frame(width: 100, height: 150)
                .aspectRatio(contentMode: .fit)
                .shadow(color:Color.accentColor, radius: 10)
        }
        VStack (alignment:.leading){
            Text(itemModel.book.name)
            
            HStack (alignment: .center){
                ProgressView(value: progress, total: 100.0)
                Text("\(String(format: "%.0f", progress)) %")
                    .font(.system(size: 13))
                    .fontWeight(.medium)
            }.padding(.horizontal, 3)
            
            Button {
                showingAlert.toggle()
            } label: {
                Text("Update Progress")
            }
            .buttonStyle(ProgressButtonModifier())

        }
    }
    .alert(itemModel.book.name, isPresented: $showingAlert) {
        TextField("Page read", text: $pageRead)
            .modifier(TextFieldModifier())
            .keyboardType(.numberPad)
        Button("Submit", action: submit)
    } message: {
        Text("what is your current page ?")
    }
    
    .toast(isPresenting: $showError){
        AlertToast(displayMode: .banner(.pop), type: .error(Color.accentColor), title: "Current page should not be more than total number of pages")
    }
    
    .padding()
    .onAppear(perform: {
        progress = getPercentage()
    })
    .modelContainer(for: [SDBook.self])
   
}

func getPercentage() -> Double{
    return Double((100 * itemModel.book.currentPage) / itemModel.book.numberOfPages)
}

func submit() {
    print("You entered \(pageRead)")
    if pageRead.toInt() > itemModel.book.numberOfPages {
        showError.toggle()
    }else{
        itemModel.book.currentPage = pageRead.toInt()
        showingAlert.toggle()

    }
}

}


Solution

  • Some issues in your code