I am developing a calendar app and I am using FSCalendar library. When I select a date from calendar, I want to show events from selected day in tableview cell. I can show all events in cell, but I am trying to filter data set for selected day, but it is not working.
I am trying to do something like this: sample
My codes:
import UIKit
import Firebase
import FSCalendar
class CalendarVC: UIViewController, UITableViewDelegate, UITableViewDataSource, FSCalendarDelegate, FSCalendarDataSource {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var calendarView: FSCalendar!
var taskArray = [String]()
var calendarTimeArray = [String]()
var documentIdArray = [String]()
var cellDateString = [String]()
var selectedDate = ""
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
calendarView.delegate = self
calendarView.dataSource = self
getDataFromFirestore()
let dateToday = Date()
let formatDate = DateFormatter()
formatDate.dateFormat = "dd.MM.yyyy"
let drawDate = formatDate.string(from: dateToday)
selectedDate = drawDate
}
func getDataFromFirestore() {
let fireStoreDatabase = Firestore.firestore()
fireStoreDatabase.collection(Auth.auth().currentUser!.email!).order(by: "calendarDate", descending: true).addSnapshotListener { (snapshot, error) in
if error != nil {
print(error?.localizedDescription ?? "Error")
} else {
if snapshot?.isEmpty != true && snapshot != nil {
self.taskArray.removeAll(keepingCapacity: false)
self.calendarTimeArray.removeAll(keepingCapacity: false)
self.documentIdArray.removeAll(keepingCapacity: false)
self.cellDateString.removeAll(keepingCapacity: false)
for document in snapshot!.documents {
let documentID = document.documentID
self.documentIdArray.append(documentID)
if let title = document.get("calendarTitle") as? String {
self.taskArray.append(title)
}
if let title = document.get("calendarTime") as? String {
self.calendarTimeArray.append(title)
let dateFormatter = DateFormatter()
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "d MMM yyyy HH:mm"
let date = dateFormatter.date(from:title)!
let formatDate = DateFormatter()
formatDate.dateFormat = "dd.MM.yyyy"
let drawDate = formatDate.string(from: date)
self.cellDateString.append(drawDate)
}
}
self.tableView.reloadData()
}
}
}
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
let formatter2 = DateFormatter()
formatter2.dateFormat = "dd.MM.yyyy"
let string2 = formatter2.string(from: date)
selectedDate = string2
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let compare = cellDateString.filter { element in element == selectedDate }
return compare.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CalendarCell
cell.taskLabel.text = taskArray[indexPath.row]
cell.documentIdLabel.text = documentIdArray[indexPath.row]
let cellDate = calendarTimeArray[indexPath.row]
let dateFormatter = DateFormatter()
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "d MMM yyyy HH:mm"
let date = dateFormatter.date(from:cellDate)!
let formatDate = DateFormatter()
formatDate.dateFormat = "HH:mm"
let drawDate = formatDate.string(from: date)
cell.timeLabel.text = drawDate
return cell
}
}
Currently:
The FSCalendarDelegate
method is only updating the selected date.
In numberOfRowsInSection
is filtering and counting, but you never saves the filtered results, only calculating the count.
In cellForRowAt
, no date filter is applied at all.
What you want to do is have the FSCalendarDelegate
actually save the filtered results before it calls reloadData
.
But you’re making it much harder on yourself by having the four arrays. It makes it really hard to use the values in one array to filter the other three. Instead, you should have a struct
that captures all four values, and have an array of these structures. That way, when you filter (or sort or whatever) the results, all four properties are handled together.
So, rather than four string arrays, let’s define a structure to capture four properties:
struct Event {
let task: String
let calendarTime: String
let documentId: String
let cellDate: String
}
Then you can have an array to capture the events (e.g., events
) and another to capture the events filtered for a particular date (e.g. filteredEvents
):
var events: [Event] = []
var filteredEvents: [Event] = []
So, when parsing the results, create an Event
object, and append it to events
.
When you want to filter the results in the FSCalendarDelegate
method, you’d do something like:
filteredEvents = events.filter { $0.cellDate == selectedDate }