How do I make my CollectionView Cells filter data from my TableView? - ios

I'm having an issue trying to get my collection view to filter data in the tableview for the category(s) set in the collection view. My goal is to have a category selected in the collection view presents the search results for the selected category in tableview shown from the category shown in the categoryLabel:
the tableview is already connected to the search bar and presents the search results accurately. But I want it to do the same for the selections/category(s) in the collection view to filter out the result selected to present the search results for that specific category in the collection view.
My data is stored in the Cloud Firestore
import Foundation
import UIKit
class Category {
var categoryLabel: String
init(categoryLabel: String) {
self.categoryLabel = categoryLabel
}
class func createCategoryArray() -> [Category] {
var categorys: [Category] = []
let category1 = Category(categoryLabel: "All")
let category2 = Category(categoryLabel: "Flower")
let category3 = Category(categoryLabel: "CBD")
let category4 = Category(categoryLabel: "Pre-Roll")
let category5 = Category(categoryLabel: "Pens")
let category6 = Category(categoryLabel: "Cartridges")
let category7 = Category(categoryLabel: "Concentrate")
let category8 = Category(categoryLabel: "Edible")
let category9 = Category(categoryLabel: "Drinks")
let category10 = Category(categoryLabel: "Tinctures")
let category11 = Category(categoryLabel: "Topical")
let category12 = Category(categoryLabel: "Gear")
categorys.append(category1)
categorys.append(category2)
categorys.append(category3)
categorys.append(category4)
categorys.append(category5)
categorys.append(category6)
categorys.append(category7)
categorys.append(category8)
categorys.append(category9)
categorys.append(category10)
categorys.append(category11)
categorys.append(category12)
return categorys
}
}
import UIKit
class CategoryScrollCell: UICollectionViewCell {
#IBOutlet weak var categoryScroll: UILabel!
#IBOutlet weak var view: UIView!
func setCategory(category: Category) {
categoryScroll.text = category.categoryLabel
}
}
import UIKit
import Firebase
class ProductListController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var productListCollectionView: UICollectionView!
#IBOutlet weak var productListTableView: UITableView!
var categorys: [Category] = []
var searchActive : Bool = false
var productInventory: [ProductList] = []
var productSetup: [ProductList] = []
override func viewDidLoad() {
super.viewDidLoad()
categorys = Category.createCategoryArray()
productListCollectionView.dataSource = self
productListCollectionView.delegate = self
productListTableView.dataSource = self
productListTableView.delegate = self
searchBar.delegate = self
fetchProducts { (products) in
self.productSetup = products
self.productListTableView.reloadData()
}
}
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let ref = Firestore.firestore().collection("products")
ref.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
}
}
extension ProductListController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
ProductListCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
return cell
}
}
extension ProductListController: UICollectionViewDelegate, UICollectionViewDataSource{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categorys.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryScrollCell", for: indexPath) as! CategoryScrollCell
let category = categorys[indexPath.row]
cell.setCategory(category: category)
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("selected")
self.productSetup.category = self.productInventory[indexPath.row]
}
}

As I understand your question,
First, here is my suggestion:
Don't use the UITableView and UICollectionView. No need to use two UI scroll classes together. You can achieve it using only UICollectionView.
Simply make a collectionView cell for category filter listing and returning it on the 0th index.
Now come to your problem, simply you can use the number of sections in CollectionView to show products with each filtered category.

Related

Insert two arrays in tableView - Error connecting

Edited:
I'm trying to insert two arrays into one tableview with two cell labels. But not really sure how I can convert it all and make it work. Here is my code so far.
In the top of the main ViewController (Where the tableView is)
class ScoreBoardViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
var countedArray: [String] = []
var nameArray: [String] = []
#IBOutlet weak var tableView: UITableView!
var list: [pointsTxt] = []
Additional info: I've added the self.tableView.delegate = self
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let listPath = list[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "pointsCell") as! ScoreCell
cell.setCell(list: listPath)
return cell
}
func createArray() -> [pointsTxt]
{
var tempTxt: [pointsTxt] = []
let txt = pointsTxt(person: nameArray, points: countedArray)
tempTxt.append(txt)
self.list = tempTxt
self.tableView.reloadData()
return list
}
Class for the cell
class ScoreCell: UITableViewCell
{
#IBOutlet weak var person: UILabel!
#IBOutlet weak var points: UILabel!
func setCell(list: pointsTxt)
{
person.text = list.person
points.text = list.points
}
}
ERROR: Cannot assign value of type '[String]' to type 'String?'
Class for the array
class pointsTxt
{
var person: [String] = []
var points: [String] = []
init(person: [String] = [], points: [String] = [])
{
self.person = person
self.points = points
}
}
I hope you understand what I need. Thanks in advance!
You have to follow the following steps when creating a custom tableViewCell:
Subclass UITableViewCell
Add your Outlets to that subclass
register your subclass to the TableView
code Example for your rowAtIndexPath function:
.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < nameArray.count {
// load from customerDetails array
let names = nameArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath) as! UITableViewSubclassCell
cell.person.text = names
return cell
} else {
// load from customerDetails2 array
let points = countedArray[indexPath.row - nameArray.count]
let cell = tableView.dequeueReusableCell(withIdentifier: "listCell", for: indexPath) as! UITableViewSubclassCell
cell.person.text = points
return cell
}
}

How to reload TableVIew Using Model NSObject Class with MVVM

I want to reload TableView without tableview.reloadData() method for that i have used MVVM structure so i have attach model class to storyboard and the issue is that my tableview is reload first and then i get all data how should i solved this issue please help me if any one have a solution !!
This is storyboard model attach
Model Code :-
class MovieModel: Decodable{
var artistName: String = ""
var trackName: String = ""
init(artistName: String, trackName: String){
self.artistName = artistName
self.trackName = trackName
}
}
class ResultModel: Decodable{
var results = [MovieModel]()
init(results: [MovieModel]) {
self.results = results
}
}
My ViewModel File code :-
class MovieViewModel: NSObject {
var artistName: String = ""
var trackName: String = ""
var movieModel: MovieModel?
var movieData = [MovieViewModel]()
override init() {
}
init(movie: MovieModel) {
self.artistName = movie.artistName
self.trackName = movie.trackName
}
func getData(){
Service.shareInstance.getAllMovieData { (movie, error) in
if error == nil{
self.movieData = movie?.map({return MovieViewModel(movie: $0)}) ?? []
print(self.movieData)
}else{
print("\(String(describing: error))")
}
}
}
func numberOfRow(section:Int) -> Int{
return movieData.count
}
func cellForRow(indexPath: IndexPath) -> MovieViewModel{
return self.movieData[indexPath.row]
}
}
My ViewController Code :-
class ViewController: UIViewController {
#IBOutlet var movieVM: MovieViewModel?
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.movieVM?.getData()
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movieVM?.numberOfRow(section: section) ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let movie = movieVM?.cellForRow(indexPath: indexPath)
cell?.textLabel?.text = movie?.artistName
cell?.detailTextLabel?.text = movie?.trackName
return cell!
}
}
In my case i am not reload tableview all this is done using ModelClass ! Thank You !!

How to have each UITableViewOption have its own data

I am trying to have each choice in my UITableView to have its own unique set of data. For example, in my table view I have a list of states, then when I click on a state, I want each state to have a list of cities that correspond specifically to it. I have attached my code below, the code is strictly for the UITableView only.
I'm new to Xcode/Swift.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
let textCellIdentifier = "TextCell"
var states = ["Illinois", "Indiana", "Kentucky", "Michigan", "Ohio", "Pennsylvania", "Wisconsin"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return states.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath)
let row = indexPath.row
cell.textLabel?.text = states[row]
return cell
}
private func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
let row = indexPath.row
print(states[row])
}
You can construct array model like this
struct MainItem {
var name:String
var cities:[String]
init(name:String,cities:[String]) {
self.name = name
self.cities = cities
}
}
//
let item1 = MainItem(name:"Illinois",cities:["city1","city2"])
let item2 = MainItem(name:"Indiana",cities:["city3","city4"])
var states = [item1,item2]
//
in cellForRowAt
cell.textLabel?.text = states[row].name
//
in didSelectRowAtIndexPath
let cities = states[row].cities
I recently did this by creating separate classes for each of the delegates I wanted to have. Move all of the table functions into a new class and create an instance of the class in your new controller. In the view did load function set the delegate for the first table. Whenever you switch tables with a button or whatever, do nextTable.delegate = xxxx.
View controller code:
let eventLogTableController = EventLogTableController()
let missedEventLogController = MissedEventTableController()
#IBOutlet weak var emptyTableLabel: UILabel!
#IBOutlet weak var missedEventLog: UITableView!
override func viewDidLoad() {
self.eventLog.delegate = eventLogTableController

Firebase import array data to tableview

I have tableview in VC and I would like to import "Detail" item form current recipe:
Firebase entries
to tableView - each to a separate cell.
My Code in RecipiesModel:
class RecipiesModel {
var title: String?
var desc: String?
var detail: Array<Any>?
init(title: String?, desc: String?, detail: Array<Any>?){
self.title = title
self.desc = desc
self.detail = detail
}
}
My Code in VC:
import UIKit
import FirebaseDatabase
class DescriptionViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var textInput: String = ""
var descInput: String = ""
var ref:DatabaseReference!
var recipiesList = [RecipiesModel]()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var titleLabelDesc: UILabel!
#IBOutlet weak var descriptionLabelDesc: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var tabBarView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.shared.statusBarStyle = .lightContent
tableView.delegate = self
tableView.dataSource = self
customUIView()
titleLabelDesc.text = textInput
descriptionLabelDesc.text = descInput
loadList()
}
//Database
func loadList() {
ref = Database.database().reference()
ref.child("Recipies").observe(.childAdded, with: { (snapshot) in
let results = snapshot.value as? [String : AnyObject]
let title = results?["Recipies title"]
let desc = results?["Recipies description"]
let detail = results?["Detail"]
let myRecipies = RecipiesModel(title: title as! String?, desc: desc as! String?, detail: detail as! Array<Any>?)
self.recipiesList.append(myRecipies)
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
func customUIView() {
tabBarView.layer.shadowColor = UIColor.lightGray.cgColor
tabBarView.layer.shadowOpacity = 1
tabBarView.layer.shadowOffset = CGSize.zero
tabBarView.layer.shadowRadius = 3
}
#IBAction func dismissButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
//TableView
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipiesList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDescription") as! TableViewCellDescription
let recipies = recipiesList[indexPath.row]
cell.recipiesModuleLabel.text = recipies.detail?.description
return cell
}
}
At this moment the result is:
Table View Entries
Any ideas?
In your case you want to show details items in different row whereas you have array of RecipiesModel.
var recipiesList = [RecipiesModel]()
In case you can represent each modal object of array as a section and details object as their rows. You can do that as:
// TableView datasource and delegate methods
func numberOfSections(in tableView: UITableView) -> Int {
return recipiesList.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let modal = recipiesList[section]
return "\(modal.title ?? ""): \(modal.desc ?? "")"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipiesList[section].detail?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDescription") as! TableViewCellDescription
if let detailName = recipiesList[indexPath.section].detail?[indexPath.row] as? String {
cell.recipiesModuleLabel.text = detailName
} else {
cell.recipiesModuleLabel.text = ""
}
return cell
}

How to add a cell to my Table View dynamically using a button

I am trying to add a cell to my table view with a button. Everything I have read and watched suggests that what I have written should work, but it doesn't. Any suggestions?
import UIKit
class RootViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
private var cellPointSize: CGFloat!
private var albumsList: AlbumList!
private var albums:[Album]!
private let albumCell = "Album"
#IBOutlet var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let preferredTableViewFont = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cellPointSize = preferredTableViewFont.pointSize
albumsList = AlbumList.sharedAlbumList
albums = albumsList.albums
self.myTableView.dataSource = self
self.myTableView.delegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return albums.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Albums"
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCellWithIdentifier(albumCell, forIndexPath: indexPath) as! UITableViewCell
//cell.textLabel?.font = fontForDisplay(atIndexPath: indexPath)
cell.textLabel?.text = albums[indexPath.row].name
cell.detailTextLabel?.text = albums[indexPath.row].artist
return cell
}
#IBAction func addNewAlbumAction(sender: UIBarButtonItem) {
var newAlbum = Album(nameIn: "New Title", yearIn: "New Year", artistIn: "New Artist", labelIn: "New Label")
albumsList.addAlbum(newAlbum)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.myTableView.reloadData()
})
}
func saveData(albumObject: Album) {
var archiveArray = NSMutableArray(capacity: albums.count)
for a in albums {
var albumEncodedObject = NSKeyedArchiver.archivedDataWithRootObject(a)
archiveArray.addObject(albumEncodedObject)
}
var userData = NSUserDefaults()
userData.setObject(archiveArray, forKey: "albums")
userData.synchronize()
}
My albums array is adding the data correctly. I can see the albums in the debugger. The delegate methods are never being called after the first time when the app loads. Any ideas?
in tableView:numberOfRowsInSection:, it returns albums.count
but when the button is pressed, you add the new album to albumsList
The problem is, albums will not get update.
So I think you should return albumsList.albums.count instead.
and in tableView:cellForRowAtIndexPath:, you modify the cell correspond to albumsList.albums[indexPath.row]

Resources