dot3
dot3

Reputation: 1216

Swiftui: child view does not receive updates to observableobject

I have a model which, for the sake of example, is a tag cloud and a model for items:

struct TagCloud: Identifiable, Hashable{
  var id: Int
  let tag: String

  static func tagCloud() -> [TagCloud]{
   return [ TagCloud(id: 01, tag:"Green"),
           TagCloud(id: 02, tag:"Blue"),
           TagCloud(id: 03, tag:"Red")]
  }
}

struct TaggedItem: Identifiable, Hashable{
  var id: Int
  let tag: String
  let item: String

  static func taggedItems() -> [TaggedItem]{
   return [ TaggedItem(id: 01, tag:"Green", item: "Tree"),
           TaggedItem(id: 02, tag:"Blue", item: "Sky"),
           TaggedItem(id: 03, tag:"Red", item: "Apple")...]
  }
}

I have a class to 'contain' the currently selected items:

class SelectedItems: ObservableObject {

 @Published var currentlySelectedItems:[TaggedItem]  = []

 func changeData(forTag tag: String ){
  let currentSelection = TaggedItem. taggedItems()
  let filteredList = cardCollection.filter { $0.tag == tag }
  currentlySelectedItems = filteredList
 }
}

In my parent view, I select one of the tags from the cloud:

struct ParentView: View {

 let tagCloud = TagCloud.tagCloud()
 @ObservedObject var currentSelection : TaggedItem = TaggedItem()
 @State var navigationTag:Int? = nil

  var body: some View {
   NavigationLink(destination: ChildView(), tag: 1, selection: $tag) {
    EmptyView()
   }

   VStack{
    ScrollView(.horizontal, content: {
     HStack(spacing: 20){
      ForEach( self.tagCloud, id: \.self) { item in
       VStack{
        Button(action: {
         self. currentSelection.changeData(forTag: item.tag )
         self.navigationTag = 1
        }){
         Text(item.tag)
        }.buttonStyle(PlainButtonStyle())
  ..  
}

The child view contains the ObservedObject. As a side note, I have also set this as an EnvironmentObject.

struct ChildView: View {

 @ObservedObject var currentItems : SelectedItems = SelectedItems()

 var body: some View {
  VStack{
   ScrollView(.horizontal, content: {
    HStack(spacing: 20){
     ForEach( currentItems.currentlySelectedItems, id: \.self) { item in
...

The problem:

I tried a number of things with init(). I tried passing the selected tag to the child, and then doing the filtering within init() itself, but was stymied by the need to bind to a class. I read elsewhere to try having a second model which would be updated by the FIRST model in order to trigger a view refresh.

What is the correct way to create this filtered list via a parent view selection and make the list available in the child view?

Upvotes: 1

Views: 133

Answers (1)

Asperi
Asperi

Reputation: 257493

This part should be rethink:

let tagCloud = TagCloud.tagCloud()
@ObservedObject var currentSelection : TaggedItem = TaggedItem()
                                       ^^ is a struct, it cannot be observed !!! 

@ObservedObject must be applied only to @ObservableObject as you did for SelectedItems, so probably another ObservableObject view model wrapper around TaggedItem is expected here.

Upvotes: 1

Related Questions