Reputation: 3099
I have textfields that are a couple views deep. I am trying to pull the inputed data to send to a server. Has anyone found an example of pulling data that is deep nested in views?
Here is the structure of this feature..
symbol: > NavigationLink
symbol: ~ Subview
HostingViewController ~ CustomListView > FormTypeView > BuildFormView (Has ObservedObject constructed here) ~ ViewPagerView (Horizontal List Of PageViews) ~ FourItemCardView ~ TextFieldInputView.
Alternate Structure Outline to help explain
- HostingViewController ~ CustomListView - FormTypeView - BuildFormView ~ ViewPagerView ~ FourItemCardView ~ TextFieldInputView
When you click "Add" in the ListView, you choose from a form type, and then the BuildFormView creates a multi-card swipe-able view pager. This is built inside ObservableObject.
In a perfect world all my data would bind to..
@Published var pageCells: [PageViewCell] = [PageViewCell]()
Where I could call it in ObservableObject's buildFormData1()..
let headline: String = pageCells[0].valueOne
let location: String = pageCells[0].valueTwo
let isPrivate: String = pageCells[0].valueFour
I have managed view binding in swiftui, and callbacks upon a button press, but to bind a view or callback 2-3 levels doesn't seem to work.
I have tried EnvironmentalObject which sort of breaks. I can't use it in SceneDelegate since I have my HostingViewController in storyboard. I can define it where I connect the CustomListView to the HostingViewController, but that crashes ( can't remember the reason off my head ). Even if this did work to obtain the data specific would be difficult. As my view pager is dynamically changing I can't individually define every variable in my ObservedObject.
Has anyone found an example of pulling data that is deep nested? I can't avoid the nesting either because SwiftUI breaks (a misleading error) whenever you have too many views. Also let me know what code to post since there is a ton I could post which might over complicate this question.
Upvotes: 1
Views: 357
Reputation: 257711
Here is possible approach based on view preferences. The demo replicates simple hierarchy for your last four views and shows how to transfer text entered in the last view to the very top view in hierarchy.
// Models
struct TextValueKey: PreferenceKey { // view pref for transfer
static var defaultValue: String = ""
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}
class BuildFormViewModel: ObservableObject { // view model on top
@Published var value: String = ""
}
// Views
struct BuildFormView: View {
@ObservedObject var vm = BuildFormViewModel()
var body: some View {
VStack {
Text("Current: \(vm.value)")
Divider()
FourItemCardView()
.onPreferenceChange(TextValueKey.self) {
self.vm.value = $0 // consume value
}
}
}
}
struct ViewPagerView: View {
var body: some View {
FourItemCardView()
}
}
struct FourItemCardView: View {
var body: some View {
TextFieldInputView()
}
}
struct TextFieldInputView: View {
@State private var text: String = ""
var body: some View {
TextField("Placeholder", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle()).padding()
.preference(key: TextValueKey.self, value: text) // inject value
}
}
Upvotes: 2