Pass editingDidChange Text Value From TableView Cell to Model - arrays

I have a TableView with multiple sections and would like to use editingDidChange in each cell to update the text fields. I can pass data easily enough from the UITableView cell's class to the ViewController that will update the array model, however I can't think of a way to pass along info on which cell is being edited (and therefore which index in the array should be changed).
I've used sender.tag in similar scenarios before, however the tag's only count up from each section when headers are involved. How can I tell the ViewController what cell is being edited?
Thanks!
//TableView cell class
#IBAction func textField(_ sender: UITextField) {
updateTextForDelegate.didUpdate(text: sender.text ?? "") //using editingDidChange
}

you can use like this to get cell indexpath.row for finding which cell editing.
func textFieldDidBeginEditing(_ textField: UITextField) {
var v : UIView = textField
repeat { v = v.superview! }
while !(v is UITableViewCell)
let cell = v as! FeedbackTableViewCell // or UITableViewCell or whatever
let ip = self.tableview.indexPath(for: cell)
textField.text = cell.anstxt.text
// and now we have the index path! update the model
let arrlist = arrfeedback[ip?.row ?? 0]
}

In your cellForRowAt method, you can assign your textField tag as follows:
cell.yourTextField.tag = (indexPath.section * 100) + (indexPath.row)
Then in your textFieldDidBeginEditing you can get the indexPath as follows:
func textFieldDidBeginEditing(_ textField: UITextField) {
let tag = textField.tag
let sectionBeingEdited = tag / 100
let rowBeingEdited = tag%100
let indexPath = IndexPath(row: rowBeingEdited, section: sectionBeingEdited)
let cell = self.servicesTable.cellForRow(at: indexPath)
// you have got your cell
}
NOTE: This is just a hack to get the indexPath considering the max
number of section could be 100. You can increase the value from 100 to whatever you want.

Related

How to append array of value into tableView in iOS Swift?

TableView consists with list of dynamic label and navigation bar consists of two button called up and down.
here i'm getting data from json and append to model. But i can not able to list in tableview. Array value should be loaded to list of label.
Here is my json appended to model:
[PO_PR.poItemsModel(Material: Optional("RMECC_MOB1"), Qty: Optional("2.000"), UoM: Optional("KG"), totalValue: Optional("1000.000"), Requistor: Optional(""), StorageLocation: Optional("3001"), MatGrp: Optional("00107"), valuationPrice: Optional("1000.000"), ItemCategory: Optional("0"), lineNo: Optional("00010"), UnitofPrice: Optional("1.000")),
PO_PR.poItemsModel(Material: Optional("RMECC_MOB1"), Qty: Optional("2.000"), UoM: Optional("KG"), totalValue: Optional("1000.000"), Requistor: Optional(""), StorageLocation: Optional("3001"), MatGrp: Optional("00107"), valuationPrice: Optional("1000.000"), ItemCategory: Optional("0"), lineNo: Optional("00020"), UnitofPrice: Optional("1.000"))]
Initially array of first index should be loaded to list of label and then when pressing down button next of array value should be loaded to list of label.
Labels in tableview will be in each cell not in a single cell.
Here is my model:
struct poItemsModel {
var Material : String?
var Qty : String?
var UoM : String?
var totalValue : String?
var Requistor : String?
var StorageLocation: String?
var MatGrp : String?
var valuationPrice : String?
var ItemCategory : String?
var lineNo : String?
var UnitofPrice : String?
init(json: JSON) {
Material = json["Material"].stringValue
Qty = json["Quantity"].stringValue
UoM = json["OrderUnit"].stringValue
totalValue = json["NetPrice"].stringValue
Requistor = json["Requistor"].stringValue
StorageLocation = json["StorageLocation"].stringValue
MatGrp = json["MatGroup"].stringValue
valuationPrice = json["NetPrice"].stringValue
ItemCategory = json["ItemCat"].stringValue
lineNo = json["Item"].stringValue
UnitofPrice = json["UnitofPrice"].stringValue
}
}
Here i'm appeding json data to model:
func GetPoItemCount() {
if orderNo != nil {
// Call API
print("orderni::\(orderNo!)")
PoVendorListApiManager.sharedInstance.getPoListWithModel(orderString: orderNo!){ (json:JSON) in
// return json from API
if let results = json["d"]["results"].array {
print("catefory::\(results)")
for category in results {
self.PoItemsArray.append(poItemsModel(json: category))
for (key, value) in category {
print("keyvalue\(key)\(value)")
self.poItemJsonArray.append(value)
self.poItemKeyArray.append(key)
let currency = newPrItemDetailModel(key: key, value: value)
self.newItemDetailsArray.append(currency)
}
}
let elm = self.PoItemsArray
let mirror = Mirror(reflecting: elm)
for child in mirror.children {
print("key: \(String(describing: child.label)), value: \(child.value)")
}
print("self.PoItemsArray array:::\(self.PoItemsArray)")
print("new model array:::\(self.newItemDetailsArray)")
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
}//extension
Here is my tableview code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// PoItems = loadPoItems()
print("count::itemArray::\(self.PoItemsArray.count)")
return PoItemsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! PoItemTableViewCell
let itemDetails = PoItemsArray[indexPath.row]
// for arrayData in
// PoItems = loadPoItems()
// prItem.getProperty(at: indexPath.row)
// cell.materials.text = PoItemsArray[0].key!
// cell.materialsValue.text = itemDetails[indexPath.row]
return cell
}
Here is my screenshot where i'm trying to achieve:
How to load to array of first index into list of dynamic labels and when pressing down button how to load next array index of values into list of dynamic labels.
Any help much appreciated pls....
This can not be done (realistically) with a table view. Table views are for long lists (a variable number) of the same item which can not change. What you have here is a fixed number (9) of totally different items, which do change.
Answer 1:
Do not use a table view for this. It's not what a table view is for.
Simply use a StackView for your layout - it's dead easy, and still scrolls etc.
Done. It will take 2 minutes.
Answer 2:
If as an exercise you want to use a table view, which would be wrong:
To do "synced / dynamic" tables is extremely difficult.
You must have a custom cell class
The button (on the main screen) must signal in some way to all of the cells to make the change in question.
This is a broad field of enquiry, you'd have to look in to the various ways to achieve this.

swift auto refresh Cell

which I add or remove from another ViewController
Im display this array.count in tableView
How in swift I can auto updates cell for array.count?
without Timer and Pull to refresh
Or how can I make refresh when loadedCart.count haw change?
Thanks
class TestTABLEVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableViewT: UITableView!
var CellT = TestTableViewCell()
var def = UserDefaults.standard
var loadedCart = [[String:Any]]()
override func viewDidLoad() {
super.viewDidLoad()
tableViewT.estimatedRowHeight = 100
tableViewT.dataSource = self
tableViewT.delegate = self
loadedCart = UserDefaults.standard.array(forKey: "cartt") as? [[String: Any]] ?? []
//Here need add auto update
}
cell for row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TestTableViewCell
let item = loadedCart[indexPath.row]
cell.nameLbl?.text = item["name"] as? String
cell.priceLbl.text = item["price"] as? String
cell.qntLbl.text = item["qty"] as? String
let im = item["image"] as? NSData
cell.PhoroUmage.image = UIImage(data: im! as Data)
return cell
}
Btn, when click - remove arr and reload cells
#IBAction func Btn(_ sender: UIButton) {
def.removeObject(forKey: "cartt")
print("remove is OK")
//Here need add auto update when btn pressed
}
If I understand you correctly, you can use reactive programming for this. For example Bond framework can be used like this:
let todoItems: SafeSignal<[TodoItem]> = ....
let tableView: UITableView = ...
class TodoItemCell: UITableView Cell { ... }
...
todoItems.bind(to: tableView, cellType: TodoItemCell.self) { (cell, item) in
cell.titleLabel.text = item.name
}
Using this framework, your table view will automatically reload when there are any changes to the source array. You will find more about usage on table views at this link.
you probably need to use notifications. i.e. send a notification when something new gets added to your cart.
Then set up an observer and, every time the observer notices a change, update the tableview with reload data.
A similar use case is listed here I think but would need to be adapted for your needs (if you need more help someone more expert than me will be able to help probably with the specifics!) Automatically Reload TableViewController On Rewind
Add
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let carts = UserDefaults.standard.array(forKey: "cartt") as? [[String: Any]] {
loadedCart = carts
}
DispatchQueue.main.async{
self.tableViewT.reloadData()
}
}

how can I refer to UILabel or UIButton collections indexPath in array

#IBOutlet var buttons: [UIButton]!
#IBOutlet var labels: [UILabel]!
#IBAction func cevapSeçildi(_ sender: UIButton) {
if sender == buttons[0] {
`enter code here`
labels[0].backgroundColor = UIColor.yellow
}
}
I want this ..
var x : Int
if sender == buttons[x] { labels[x].backgroundColor = UIColor.yellow }
can you help me please
A couple of points:
Using your array of buttons to map to cell indexes will only work for a single-section table view or collection view. If you have a sectioned table view or a collection view that's in rows and columns then that approach won't work.
If you want to make the label yellow on the selected cell but white for all others, it doesn't make sense to change ALL the cells. A table view/collection view only shows a few cells at a time, and as you scroll, the cells get recycled and used for different indexes in your table view/collection view.
If you let me know whether you're using a table view or a collection view I can show you a better way to do this.
EDIT:
Since you're not using a table view or collection view, it does make sense to manipulate the labels directly:
#IBAction func cevapSeçildi(_ sender: UIButton) {
let buttonIndex = buttons.index(of: sender)
for (index, label) in labels.enumerated) {
}
if index == buttonIndex {
label.backgroundColor = UIColor.yellow
} else {
label.backgroundColor = UIColor.white
}
}
You can get the index of the button with
var index = buttons.index(of: sender)
then set
labels[index].backgroundColor = UIColor.yellow
If you would like to set all the other buttons to a different color at the same time, consider this:
let buttonIndex = buttons.index(of: sender)
for var label in labels {
if(labels.index(of: label) == buttonIndex) {
label.backgroundColor = UIColor.yellow
} else {
label.backgroundColor = UIColor.white
}
}

Segue textfields to a string array

I'm doing an app using swift that takes the entries in 6 text fields and passes them through a segue into an empty string array on a second view controller. How do I do that?
This is my code, is the basics, but I'm not sure how I can send the information through.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as! secondView
if segue.identifier == segueID {
destination.stringArray = ?
}
}
The array on my second view controller is this:
var stringArray = [String]()
The shortest way:
destination.stringArray = view.subviews.flatMap { ($0 as? UITextField)?.text }
Are your 6 textfields in an IBOutletCollection (in other words, an array of textfields) or are they each their own IBOutlet (textfield)? Either way, your question comes down to putting all of their text values in an array, which can be done like this if they're in an IBOutletCollection:
destination.stringArray = myTextFieldCollection.flatMap { $0.text }
Or, if they're not in an array:
destination.stringArray = [myTextField1, myTextField2, ...,
myTextField6].flatMap { $0.text }
I'm using flatMap in these because UITextField.text is an optional String?, so they need to be unwrapped to String, which flatMap safely does.

Creating JSON Array in Swift to update MySQL database

I hope this isn't a stupid question, I have been trawling the solutions and haven't been able to work this out..
In my main view controller I get data from a MySQL database using PHP and JSON. The user then selected relevant items from a table view by clicking on a custom button in a custom cell. I am at the point where I can add to/remove from the list based on which buttons are clicked/unclicked...
private var selectedItems = [Int: String]()
func cellButtonTapped(cell: CustomCell) {
let indexPath = self.tableView.indexPathForRowAtPoint(cell.center)!
let selectedItem = postsCollection[indexPath.row]
let item = selectedItem.product
let id = selectedItem.Id
let idItem : [Int:String] = [id:"\(item)"]
if selectedItems[id] == nil {
// now val is not nil and the Optional has been unwrapped, so use it
selectedItems[id] = "\(item)" //item
} else {
selectedItems[id] = nil
}
println("\(selectedItems)")
}
If I select items on the list it is displayed like this as I select the items. When I deselect them, the get removed from the list.
[6: Mybulen, 7: Ecotrin XL, 5: Aspen Simvastatin, 8: Lorien]
I would like to create a JSON Array and POST the array to a PHP file that I have the updates the database.. The resultant JSON Array should look something like this...
[{"Id":"6","repeatflag":"1"},{"Id":"7","repeatflag":"1"},{"Id":"5","repeatflag":"1"}]
So basically, any item I select gets added to the array with a "repeatflag" set to "1". My PHP file has a script that updates the "repeatflag" in the MySQL database. When the user is ready, they will click on a send button that will POST their selection in the the JSON Array. Hope that makes sense?
Thanks.
Well the code from you looks a little bit weird to me, maybe its because I don't know its context... But you can build an JSONArray you want like this:
class ViewController: UIViewController, UITableViewDelegate {
var jsonArrayWithItemsToSendToPHP: [[String: AnyObject]] = [[String: AnyObject]]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = postsCollection[indexPath.row]
var jsonObjectToPutToArray: [String: AnyObject] = [String: AnyObject]()
jsonObjectToPutToArray["id"] = selectedItem.Id
jsonObjectToPutToArray["name"] = selectedItem.product
jsonObjectToPutToArray["repeatflag"] = 1
jsonArrayWithItemsToSendToPHP.append(jsonObjectToPutToArray)
}
}
class ViewController: UIViewController, UITableViewDelegate {
var jsonArrayWithItemsToSendToPHP: [[String: AnyObject]] = [[String: AnyObject]]()
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = postsCollection[indexPath.row]
var jsonObjectToPutToArray: [String: AnyObject] = [String: AnyObject]()
jsonObjectToPutToArray["id"] = selectedItem.Id
jsonObjectToPutToArray["name"] = selectedItem.product
jsonObjectToPutToArray["repeatflag"] = 1
jsonArrayWithItemsToSendToPHP.append(jsonObjectToPutToArray)
}
}

Resources