Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Published property not updating view from nested view model - SwiftUI

Tags:

swiftui

I'm unsure why my view isn't getting updated when I have a view model nested inside another. My understanding was that a @Published property in the child view model would trigger a change in the parent viewModel, causing that to push changes to the UI.

This is the child view model:

class FilterViewModel : ObservableObject, Identifiable {

    var id = UUID().uuidString
    var name  = ""
    var backgroundColour = ""
    @Published var selected = false

    private var cancellables = Set<AnyCancellable>()

    init(name: String){
        self.name = name
    
        $selected.map { _ in
            self.selected ? "Orange" : "LightGray"
        }
        .assign(to: \.backgroundColour, on: self)
        .store(in: &cancellables)
     }

    func changeSelected() {
    
        self.selected = !self.selected
    }
}

The following works as expected, on clicking the button the background colour is changed.

struct ContentView: View {

    @ObservedObject var filterVM = FilterViewModel(name: "A")


    Button(action: { filterVM.changeSelected()}, label: {
        Text(filterVM.name)
            .background(Color(filterVM.backgroundColour))
    })
}

However, I want to have an array of filter view models so tried:

class FilterListViewModel: ObservableObject {

    @Published var filtersVMS = [FilterViewModel]()

    init(){
        filtersVMS = [
            FilterViewModel(name: "A"),
            FilterViewModel(name: "B"),
            FilterViewModel(name: "C"),
            FilterViewModel(name: "D")
        ]
    }
}

However, the following view is not updated when clicking the button

struct ContentView: View {

    @ObservedObject var filterListVM = FilterListViewModel()

    Button(action: { filterListVM[0].changeSelected()}, label: {
        Text(filterListVM[0].name)
            .background(Color(filterListVM[0].backgroundColour))
    })
}
like image 992
Spdollaz Avatar asked Oct 23 '25 02:10

Spdollaz


1 Answers

Alternate solution is to use separated view for your sub-model:

struct FilterView: View {
    @ObservedObject var filterVM: FilterViewModel

    var body: some View {
      Button(action: { filterVM.changeSelected()}, label: {
        Text(filterVM.name)
            .background(Color(filterVM.backgroundColour))
      })
    }
}

so in parent view now we can just use it as

struct ContentView: View {

    @ObservedObject var filterListVM = FilterListViewModel()

    // ...

    FilterView(filterVM: filterListVM[0])
}
like image 131
Asperi Avatar answered Oct 25 '25 20:10

Asperi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!