How to change clicked cell button label with JSON response in swift - json

In my tableview cell i added awerdedBtnLabel and awardedBtn.. if i tap button on any one cell then i need to change only tapped cell label text
code for tableview: with the below code if i click on any one cell awardedBtn then all cells awerdedBtnLabel text is changing, why?
how to change label text only on clicked cell, please do guide me
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewproposalData?.result?.bids?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewProposalTableVIewCell", for: indexPath) as! ViewProposalTableVIewCell
let bidData = viewproposalData?.result?.bids?[indexPath.row]
cell.propAmt.text = "$\(bidData?.amount ?? "")"
cell.awardedBtn.tag = indexPath.row
cell.awardedBtn.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside)
let postServData = viewproposalData?.result?.posted_services
if postServData?.is_awarded == "Y"{
cell.awerdedBtnLabel.text = "Rewoke Award"
cell.milestoneView.isHidden = false
}else{
cell.awerdedBtnLabel.text = "Award"
cell.milestoneView.isHidden = true
}
return cell
}
#objc func connected(sender: UIButton){
}
EDIT: according mentioned answer i have tried like below.. but nothing changing now.. i mean not all cells or not a single.. the button label text remains same.. if i tap on any button then no change in label
class ViewProposalTableVIewCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource {
var onAwardBtn: ((_ isAwarded: String) -> Void)?
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewproposalData?.result?.bids?.count ?? 0//5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewProposalTableVIewCell", for: indexPath) as! ViewProposalTableVIewCell
let postServData = viewproposalData?.result?.posted_services
let isAwarded = postServData?.is_awarded
cell.onAwardBtn = { [weak self] (isAwarded) in
if isAwarded == postServData?.is_awarded {
cell.awerdedBtnLabel.text = "Rewoke Award"
cell.milestoneView.isHidden = false
}
else{
cell.awerdedBtnLabel.text = "Award"
cell.milestoneView.isHidden = true
}
}
2nd Edit:
JSON response from console:
JSON {
jsonrpc = "2.0";
result = {
bids = (
{
amount = 100;
id = 153;
"get_bid_user" = {
address = dfsdffafadf;
};
},
);
"posted_services" = {
"is_awarded" = Y;
};
};
}

Related

Unable to Expand and Collapse TableViewCell in Swift

I have taken two prototype cells called CategoryTableCell and SubCategoryTableCell in tableview
Initially, I need to show all CategoryTableCell data in TableView. Here if I click CategoryTableCell then I need to show that Category's subcategories in SubCategoryTableCell. How to do that?
I need to hide all subcategories. If I click any one category from CategoryTableCell then I need to its subcategories.
Code:
extension CategoryVC: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return self.activeCategories?.count ?? 0 : 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.activeCategories?[section].sub_categories?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCategoryTableCell", for: indexPath) as! SubCategoryTableCell
cell.selectionStyle = .none
let activesubCat = self.activeCategories?[indexPath.section].sub_categories
let indexData = activesubCat?[indexPath.row]
cell.lblTitle?.text = langType == .en ? indexData?.details?.first?.title : indexData?.details?[1].title
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = tableView.dequeueReusableCell(withIdentifier: "CategoryTableCell") as! CategoryTableCell
let indexData = self.activeCategories?[section]
view.btnDetails?.tag = section
view.lblTitle?.text = langType == .en ? indexData?.details?.first?.title : indexData?.details?[1].title
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return isFromFilter ? 40 : 0
}
With the code, I am getting all categories in red colour and subcategories in dark grey colour text. But, here cell is not expanding and collapse. I need to show all red colour text initially. Here if I tap on the cell then it has to expand and show all grey colour text. How to do that? Please do help with the code.
o/p: coming like this with above code
[![screenshot][1]][1]
EDIT
JSON Model:
public class Category_json {
public var id : Int?
public var status : String?
public var sub_categories : Array<Sub_categories>?
var isExpanded = true
required public init?(dictionary: NSDictionary) {
id = dictionary["id"] as? Int
status = dictionary["status"] as? String
if (dictionary["sub_categories"] != nil) { sub_categories = Sub_categories.modelsFromDictionaryArray(array: dictionary["sub_categories"] as? NSArray ?? NSArray()) }
if (dictionary["details"] != nil) { details = Details.modelsFromDictionaryArray(array: dictionary["details"] as? NSArray ?? NSArray()) }
}
public func dictionaryRepresentation() -> NSDictionary {
let dictionary = NSMutableDictionary()
dictionary.setValue(self.id, forKey: "id")
dictionary.setValue(self.status, forKey: "status")
return dictionary
}
}
and public var activeCategories : Array<Category_json>?
EDIT2:
#objc func expandMe() {
print("expand me")
}
Add a property to your activeCategories array 's model
var isExpanded = true
Then inside numberOfRowsInSection
guard let item = self.activeCategories?[section] else { return 0 }
return item.isExpanded ? (item.sub_categories?.count ?? 0) : 0
Then play with isExpanded and refresh the table
Edit
Inside viewForHeaderInSection
let header = tableView.dequeueReusableCell(withIdentifier: "CategoryTableCell") as! CategoryTableCell
button.tag = section
Then inside action
#objc headerClicked(_ sender:UIButton) {
let section = sender.tag
guard let item = self.activeCategories?[section] else { return 0 }
item.isExpanded.toggle()
tableView.reloadData()
}

How to show rows in tableview according to textfield's search result

initially I am able to show all rows in tableview.. now i need to show only searched textfield rows...
here the textfield and search button is outside the tableview.. now if i add date in textfield and tap on search button then i need to show only the date contain row only in tableview how to do that
code to show all rows in tableview: here in postedServicesCall param's from_date is nil then i need to show all rows .. which i am able to do with below code.. now how to show if there is a value in from_date then only the date contained rows in tableview
class PageContentViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var fromDateTextField: MDCTextField!
private var servicesArray = [ServicesModel]()
override func viewDidLoad() {
postedServicesCall()
DispatchQueue.main.async {
self.servicesTableView.reloadData()
}
}
func postedServicesCall(){
let param = ["from_date" : ""]
APIReqeustManager.sharedInstance.serviceCall(param: param as [String : Any], method: .post, loaderNeed: false, loadingButton: nil, needViewHideShowAfterLoading: nil, vc: self, url: CommonUrl.posted_requests, isTokenNeeded: true, isErrorAlertNeeded: true, isSuccessAlertNeeded: false, actionErrorOrSuccess: nil, fromLoginPageCallBack: nil) { [weak self] (resp) in
self?.postedServicesData = Posted_services_base_model(dictionary: resp.dict as NSDictionary? ?? NSDictionary())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return servicesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ServicesTableViewCell", for: indexPath) as! ServicesTableViewCell
cell.serviceTitle.text = servicesArray[indexPath.row].title
cell.dateLabel.text = servicesArray[indexPath.row].date
cell.locationLabel.text = servicesArray[indexPath.row].location
return cell
}
//if i add date in textfield and tap on search.. then with the date how many rows are there should be display in tableview
#IBAction func searchtBtn(_ sender: TransitionButton) {
}
if i search date in textfield then i need to show the date related rows in tableview.. how?
please do help with code
try this easy search implementation
//
// ViewController.swift
//
// Created by Rajesh Gandru on 4/12/21.
//
import UIKit
//MARK:- User Model Class
struct User {
var userName: String?
var userNumber : String?
var UserAge : String?
}
//MARK:- tableview cell
class ExampleCell:UITableViewCell{
#IBOutlet weak var resultLBLref:UILabel!
}
class ViewController: UIViewController {
//MARK:- Class Outlets...
#IBOutlet weak var searchtextfeildref: UITextField!
#IBOutlet weak var tableViewref: UITableView!
//MARK:- Class Properties...
var listArr : [User] = []
var filteredlistArr :[User] = []
var searchMyOrders = false
//MARK:- View Lyfe cycle starts here..
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.listArr = [User(userName: "Raj", userNumber: "78623", UserAge: "34"),User(userName: "Ram", userNumber: "67467645", UserAge: "22"),User(userName: "Raki", userNumber: "5634534", UserAge: "43"),User(userName: "Raksha", userNumber: "098098", UserAge: "18"),User(userName: "Ravi", userNumber: "7863846", UserAge: "24")]
self.searchtextfeildref.addTarget(self, action: #selector(self.textFieldDidChange(_:)),
for: UIControl.Event.editingChanged)
}
//MARK:- Textfeild Search
#objc func textFieldDidChange(_ textField: UITextField) {
// filter tableViewData with textField.text
let searchText = textField.text
//by_bus_cities_drop_address
filteredlistArr = self.listArr.filter {
return (($0.userName?.localizedLowercase.contains(searchText!))! ||
$0.userNumber!.localizedLowercase.contains(searchText!))
} ?? []
if(filteredlistArr.count == 0){
searchMyOrders = false;
} else {
searchMyOrders = true;
}
self.tableViewref.reloadData()
}
}
//MARK:- Tableview Content
extension ViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchMyOrders {
return filteredlistArr.count
}else {
return listArr.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExampleCell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
if searchMyOrders {
cell.resultLBLref.text = filteredlistArr[indexPath.row].userName
}else {
cell.resultLBLref.text = listArr[indexPath.row].userName
}
return cell
}
}

Trying to reference each item of custom type for tableView cells

I am parsing data from a JSON file and I've created a struct to hold that data. I am trying to display each item of the custom struct in a tableView, but I'm getting stuck on how I should reference each item.
Here's my struct:
struct Country: Codable {
var id: Int
var country: String
var capital: String
var nationalLanguage: [String]
var population: Int
}
And here is my table view controller. Right now I only know how to reference a single item in my custom type. This obviously sets all of the cells to that one item.
class TableViewController: UITableViewController {
var countryItem: Country?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cells", for: indexPath)
if let country = countryItem {
cell.textLabel!.text = String(country.population)
}
return cell
}
}
When I print out my countryItem variable, this is what I get:
Country(id: 1, country: "United States", capital: "Washington D.C.", nationalLanguage: ["English"], population: 328239523)
Do I need to somehow set that as an array so I can refer to each item individually?
UPDATED:
Option1
class TableViewController: UITableViewController {
var countryItem: Country?
var arrayStrings: [String] {
guard let countryItem = countryItem else { return [] }
return [
"\(countryItem.id)",
countryItem.country,
countryItem.capital,
countryItem.nationalLanguage.joined(separator: ", "),
"\(countryItem.population)",
]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayStrings.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cells", for: indexPath)
cell.textLabel!.text = arrayStrings[indexPath.row]
return cell
}
}
Option2
class TableViewController: UITableViewController {
var countryItem: Country?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryItem == nil ? 0 : 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cells", for: indexPath)
let text: String
switch indexPath.row {
case 0:
text = "\(countryItem!.id)"
case 1:
text = countryItem!.country
case 2:
text = countryItem!.capital
case 3:
text = countryItem!.nationalLanguage.joined(separator: ", ")
case 4:
text = "\(countryItem!.population)"
default:
break
}
cell.textLabel!.text = text
return cell
}
}
If you all you want is just display string representation of all fields in your struct, then yes, convert them into a single array of string and use reusable cells to render.
If you need different styles for each field, then you may not need an array, just create some custom cells and then assign data for them from the struct.
Or maybe you don't even need a table view here since I see you have only one Country and no reusable needed here. Just create a custom view with 5 (maybe) labels and display your data.
For some reason, you still need a table view, then create a single cell that can display all information for your country.
Hope it can help you.
class TableViewController: UITableViewController {
var countryItem = [Country]()
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryItem.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cells", for: indexPath)
cell.textLabel!.text = countryItem[indexPath.row].country
return cell
}
}

Storing String and Int in a dictionary in swift

I'm almost new to Swift. In this URL I'll get some element; one of elements is categoryList which has two elements itself. I set the goodTypeName as the table's cell title, and when a cell is pressed it needs to send the goodType which is number (Int) to be placed in the next Url. I tried to create a dictionary but I failed!
UiTable code :::
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Global.GlobalVariable.names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if Global.GlobalVariable.names == []
{
self.DisplayMessage(UserMessage: "nothing is available ")
print("server is nil")
}
let cell = UITableViewCell()
let content = Global.GlobalVariable.names[indexPath.row]
cell.textLabel?.text = content
cell.accessoryType = .disclosureIndicator
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.item)
let next = self.storyboard?.instantiateViewController(withIdentifier: "SVC")
self.navigationController?.pushViewController(next!, animated: true)
}
My problem is not with populating them in a table, my problem is when a cell is selected , goodtype is needed to be sent to next page, becuase next page's url has to have the goodtype code.
You can use the "prepareSegue" to pass Data.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "something"{
if let startViewController = segue.destination as? StartViewController{
startViewController.goodtype = Global.GlobalVariable.goodtype[indexPath.row]
}
}
}
And in your StartViewController just assign a variable to receive your data :
var goodtype = String()
Or use the navigation controller but with this line you can access to the another view controller property.
if let startViewController = storyboard.instantiateViewController(withIdentifier: "StartViewController") as? StartViewController {
startViewController.goodtype = Global.GlobalVariable.goodtype[indexPath.row]
let navigationController = UINavigationController()
navigationController.pushViewController(startViewController, animated: true)
}

Create UITableView with multiple Custom Cells in Swift

What is the best current way to create an UITableView with multiples Custom Cell with the storyboard and the tableView methods?
For now, I get correctly my JSON response split into 3 arrays then I want to use it to update my tableView with 3 different custom cells.
class MainViewController: UIViewController {
// MARK: - Properties
var starters = [Starter]()
var dishes = [Dish]()
var deserts = [Desert]()
// MARK: - Outlets
#IBOutlet weak var foodTableView: UITableView!
// MARK: - Functions
func updatDisplay() {
ApiHelper.getFoods { starters, dishes, deserts in
self.starters = starters
self.dishes = dishes
self.deserts = deserts
self.foodTableView.reloadData()
}
}
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
updatDisplay()
}
}
extension MainViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "StarterCell", for: indexPath)
return cell
}
}
Assuming that you have the three sections "starters", "dishes" and "deserts" you can display the cells like this:
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return starters.count
}
else if section == 1 {
return dishes.count
}
else {
return deserts.count
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Starters"
}
else if section == 1 {
return "Dishes"
}
else {
return "Deserts"
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
return tableView.dequeueReusableCell(withIdentifier: "StarterCell", for: indexPath)
}
else if indexPath.section == 1 {
return tableView.dequeueReusableCell(withIdentifier: "DishesCell", for: indexPath)
}
else {
return tableView.dequeueReusableCell(withIdentifier: "DesertsCell", for: indexPath)
}
}