alopezh
(Alberto López Herranz)
1
I am trying to implement a list functionality similar to to Handling User Input example, the interface shows a list the user can filter depending on boolean values. I want to add the following differences from the example:
- Can edit list elements from the row itself
- Move the filter logic to a ViewModel class
I've tried many approaches without success one of them:
class TaskListViewModel : ObservableObject {
private var cancelables = Set<AnyCancellable>()
private var allTasks: [Task] =
[ Task(id: "1",name: "Task1", description: "Description", done: false),
Task(id: "2",name: "Task2", description: "Description", done: false)]
@Published var showNotDoneOnly = false
@Published var filterdTasks: [Task] = []
init() {
filterdTasks = allTasks
$showNotDoneOnly.map { notDoneOnly in
if notDoneOnly {
return self.filterdTasks.filter { task in
!task.done
}
}
return self.filterdTasks
}.assign(to: \.filterdTasks, on: self)
.store(in: &cancelables)
}
}
struct TaskListView: View {
@ObservedObject private var taskListViewModel = TaskListViewModel()
var body: some View {
NavigationView {
VStack {
Toggle(isOn: $taskListViewModel.showNotDoneOnly) {
Text("Undone only")
}.padding()
List {
ForEach(taskListViewModel.filterdTasks.indices, id: \.self) { idx in
TaskRow(task: $taskListViewModel.filterdTasks[idx])
}
}
}.navigationBarTitle(Text("Tasks"))
}
}
}
struct TaskRow: View {
@Binding var task: Task
var body: some View {
HStack {
Text(task.name)
Spacer()
Toggle("", isOn: $task.done )
}
}
}
With this approach the list is filtered when the user enable the filter but when it is disabled the list lose the previously filtered elements. If I change the code to restore the filter elements like this:
$showNotDoneOnly.map { notDoneOnly in
if notDoneOnly {
return self.filterdTasks.filter { task in
!task.done
}
}
return self.allTasks
}.assign(to: \.filterdTasks, on: self)
The list lose the edited elements.
I've also tried making allTask property to a @Published dictionary by without success. Any idea on how to implement this? Is ther any better approach to do this in SwiftUi?
Thanks