[
{
"label": "Hello Workspace",
"children": [
{
"label": "Workspace A",
"children": [
{
"id": "A.1",
"label": "Data 1"
},
{
"id": "A.2",
"label": "Data 2"
},
{
"id": "A.3",
"label": "Data 3"
}
]
},
{
"label": "Workspace B",
"children": [
{
"id": "B.1",
"label": "Data 1"
},
{
"id": "B.2",
"label": "Data 2"
},
{
"label": "Entry 3",
"children": [
{
"id": "B.3.1",
"label": "Sub-Dat 1"
}
]
}
]
}
]
},
{
"label": "11 Cowork",
"children": [
{
"label": "Workspace A",
"children": [
{
"id": "11.A.1",
"label": "Data 1"
},
{
"id": "11.A.2",
"label": "Data 2"
}
]
}
]
}
]
struct TreeNode: Identifiable, Codable { var id: String let label: String var children: [TreeNode]?
private enum CodingKeys: String, CodingKey {
case id
case label
case children
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .label)
self.label = try container.decode(String.self, forKey: .label)
self.children = try container.decodeIfPresent([TreeNode].self, forKey: .children)
}
}
import SwiftUI
struct ChildrenView: View {
@StateObject private var vm: ChildrenViewModel
@State private var hasAppeared = false
@State private var isEditing = false
init() {
_vm = StateObject(wrappedValue: ChildrenViewModel())
}
var body: some View {
NavigationStack {
ZStack {
background
if vm.isLoading {
ProgressView()
} else {
List {
ForEach(vm.nodes, id:\.id) { node in
ChildRowView(node: node)
}
.onDelete(perform: { indexSet in
// TODO - Implement delete functionality
})
.onMove(perform: { indices, newOffset in
// TODO - Implement move functionality
})
}
.background(Theme.background)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
}
.environment(\.editMode, isEditing ? .constant(.active) : .constant(.inactive))
}
}
.navigationTitle("Img.ly")
.onAppear {
Task {
if !hasAppeared {
await vm.fetchChildrens()
hasAppeared = true
}
}
}
.alert("Alert", isPresented: $vm.hasError) {
Button("Retry"){
Task {
await vm.fetchChildrens()
}
}
}
}
}
}
import SwiftUI
struct ChildRowView: View {
@State private var isEditing = false
let node: TreeNode
var body: some View {
Group {
if let children = node.children, !children.isEmpty {
DisclosureGroup(isExpanded: $isEditing) {
ForEach(children) { child in
ChildRowView(node: child)
}
} label: {
Text(node.label)
}
.onTapGesture {
isEditing.toggle()
}
} else {
let _ = print("ID: \(node.id)")
Text(node.id)
}
}
.font(
.system(.headline, design: .rounded)
.bold()
)
.foregroundStyle(Theme.text)
.padding(.horizontal, 5)
.padding(.vertical, 5)
.frame(maxWidth:.infinity,alignment:.leading)
.frame(height: 50)
.background(Theme.background)
}
}
struct ChildRowView_Previews: PreviewProvider {
static var previewUser: TreeNode {
let childrenResponse = try! StaticJSONMapper.decode(file: "ChildrenStaticData", type: [TreeNode].self)
return childrenResponse.first!
}
static var previews: some View {
ChildRowView(node: previewUser)
.frame(width:300)
.background(Theme.background)
}
}
I am able to parse JSON and display label (for example: "label": "Data 1") but i want to display id also in my ChildRowView. Is there anything wrong with my Model because i am getting id same as label.
Please suggest me something, what I am doing wrong here.