Search code examples
swiftuitableviewcalendarfscalendar

How to show selected day (in Calendar) in tableviewcell


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
}
}

Solution

  • 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 }