0

cell which having two textFields... And on click ADD button I want to add that cell dynamically in tableview. And also delete row. And text on both textField should not get change during scroll and on adding new cell...

And at the end I want all text field value in array of Dictionary..

following the code I have tried

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [itemsArray count];
}

-(void) setEditing:(BOOL)editing animated:(BOOL)animated {
    [super setEditing:editing animated:animated];
    [self.tableView setEditing:editing animated:animated];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    AddItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"addItemCellIdentifier"];
    if (cell == nil) {
        cell = [[AddItemTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"addItemCellIdentifier"];
    }
    return cell;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {

       [itemsArray removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

- (IBAction)addItemBtnClick:(id)sender {


    if ([itemsArray count]) {
        [itemsArray removeLastObject];
        NSIndexPath *index = [NSIndexPath indexPathForRow:0 inSection:0];
        AddItemTableViewCell *Cell = (AddItemTableViewCell *)[self.tableView cellForRowAtIndexPath:index];
        UITextField * name = (UITextField *)[Cell.contentView viewWithTag:11];
        UITextField * Qty = (UITextField *)[Cell.contentView viewWithTag:12];
        NSMutableDictionary *item = [NSMutableDictionary new];
        [item setObject:name.text forKey:@"item"];
        [item setObject:Qty.text forKey:@"quantity"];
        [itemsArray addObject:item];
    }
    [itemsArray addObject:@{@"item":@"",@"quantity":@""}];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
Akshay Ambekar
  • 325
  • 1
  • 3
  • 14
  • may be this one helps you http://stackoverflow.com/questions/31870206/how-to-insert-new-cell-into-uitableview-in-swift/31870301#31870301 – Bhavin Bhadani Jun 21 '16 at 07:12
  • I have already implemented this... but as the number of cell increases , new cell textfields gets deallocated cell value by default... – Akshay Ambekar Jun 21 '16 at 07:24
  • @AkshayAmbekar Is your array initialised? itemsArray = `[[NSMutableArray alloc] init];` – pnizzle Jun 21 '16 at 07:42
  • Can you mention what is working, so that we know where we are starting from. If nothing is showing at all then please do mention that. – pnizzle Jun 21 '16 at 07:44
  • Above code can add cell dynamically having two text fields.... But when number of cell increases and when I scroll down and up ....And then click on add button... the new cell textfield is not blank... it contains some values which is already present in some cell – Akshay Ambekar Jun 21 '16 at 09:47
  • @AkshayAmbekar see the update to my answer. You need to start off with a small table design to understand how they work. Then you can start making more complicated designs like what you are trying to do. – pnizzle Jun 22 '16 at 01:30

3 Answers3

2

Your cell will show repeated textfield values because you are reusing them and not adjusting the cell details when a cell is now expected to represent a different object.

If you do not want this behaviour (you obviously don't) then you need to set the cell details on your dataSource. Then in cellForRowAtIndexPath() you populate the current cell with the respective object details. Or, which I do not advise, you can alloc init a new cell in cellForRowAtIndexPath() for each item you add. This will use up more memory unnecessarily when you have cells that are not visible on screen.

Here is an example: this was written quickly to only demonstrate dynamically populating cells from a datasource, everything else is not a suggestion.

#import "PeopleTableViewController.h"

//--- Person Class
@interface Person : NSObject<UITextFieldDelegate>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *surname;
@end
@implementation Person
@end
//---

#define CELL_HEIGHT 80.0f
#define TEXTFIELD_HEIGHT 30.0f
#define TEXTFIELD_WIDTH 120.0f
#define TEXT_FIELD_VERTICAL_MARGIN (CELL_HEIGHT - (TEXTFIELD_HEIGHT*2)) / 3
#define TEXT_FIELD_LEFT_MARGIN 20.0f
//--- Person Cell
@class PersonCell;
@protocol  PersonCellTextFieldProtocol <NSObject>
-(void)personCell: (PersonCell*)cell nameTextfieldDidChange: (NSString*)newText;
-(void)personCell: (PersonCell*)cell surnameTextfieldDidChange: (NSString*)newText;
@end
@interface PersonCell : UITableViewCell<UITextFieldDelegate>
@property (nonatomic, strong) UITextField *nameTextField;
@property (nonatomic, strong) UITextField *surnameTextField;
@property (nonatomic, strong) UILabel *positionLabel;
@property (nonatomic, assign) id<PersonCellTextFieldProtocol> delegate;
@end
@implementation PersonCell
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self)
        [self setupSubviews];
    return self;
}
-(void)setupSubviews
{
    NSUInteger nameTextFieldYPosition = TEXT_FIELD_VERTICAL_MARGIN;

    self.nameTextField = [[UITextField alloc] initWithFrame: CGRectMake(TEXT_FIELD_LEFT_MARGIN, nameTextFieldYPosition, TEXTFIELD_WIDTH, TEXTFIELD_HEIGHT)];
    self.nameTextField.borderStyle = UITextBorderStyleRoundedRect;
    self.nameTextField.placeholder = @"Name";
    self.nameTextField.delegate = self;
    [self.nameTextField addTarget:self action:@selector(nameTextFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
    [self.contentView addSubview: self.nameTextField];

    self.surnameTextField = [[UITextField alloc] initWithFrame: CGRectMake(TEXT_FIELD_LEFT_MARGIN, CGRectGetMaxY(self.nameTextField.frame) + TEXT_FIELD_VERTICAL_MARGIN, TEXTFIELD_WIDTH, TEXTFIELD_HEIGHT)];
    self.surnameTextField.borderStyle = UITextBorderStyleRoundedRect;
    self.surnameTextField.placeholder = @"Surname";
    self.surnameTextField.delegate = self;
    [self.surnameTextField addTarget:self action:@selector(surnameTextFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
    [self.contentView addSubview: self.surnameTextField];

    self.positionLabel = [[UILabel alloc] initWithFrame: CGRectMake(5, 0, 10, 20)];
    self.positionLabel.font = [UIFont systemFontOfSize: 10];
    [self.contentView addSubview: self.positionLabel];
    self.positionLabel.center = CGPointMake(self.positionLabel.center.x, self.contentView.center.y);
}

-(void)layoutSubviews
{
    self.positionLabel.center = CGPointMake(self.positionLabel.center.x, self.contentView.center.y);
}

-(void)nameTextFieldDidChange:(UITextField*)textField
{
    if([self.delegate respondsToSelector: @selector(personCell:nameTextfieldDidChange:)])
        [self.delegate personCell:self nameTextfieldDidChange:textField.text];
}

-(void)surnameTextFieldDidChange:(UITextField*)textField
{
    if([self.delegate respondsToSelector: @selector(personCell:surnameTextfieldDidChange:)])
        [self.delegate personCell:self surnameTextfieldDidChange:textField.text];
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}
@end
//---

@interface PeopleTableViewController ()<PersonCellTextFieldProtocol>
@end

@implementation PeopleTableViewController
{
    NSMutableArray *_peopleArray;
}

-(void)viewDidLoad
{
    _peopleArray = [[NSMutableArray alloc] init];
    [self.tableView reloadData];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    PersonCell *cell = nil;
    cell = [tableView dequeueReusableCellWithIdentifier: @"CellWithNameAndSurname"];
    if(!cell)
    {
        cell = [[PersonCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CellWithNameAndSurname"];
        cell.contentView.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent: 0.08f];
        cell.delegate = self;
    }

    //this should be outside the above if statement!
    Person *respectivePerson = _peopleArray[indexPath.row];
    cell.nameTextField.text = respectivePerson.name;
    cell.surnameTextField.text = respectivePerson.surname;
    cell.positionLabel.text = [NSString stringWithFormat:@"%i", (int)indexPath.row];

    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return CELL_HEIGHT;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _peopleArray.count;
}

-(void)personCell:(PersonCell *)cell nameTextfieldDidChange:(NSString *)newText
{
    Person *respectivePerson = _peopleArray[[self.tableView indexPathForCell: cell].row];
    respectivePerson.name = newText;
}

-(void)personCell:(PersonCell *)cell surnameTextfieldDidChange:(NSString *)newText
{
    Person *respectivePerson = _peopleArray[[self.tableView indexPathForCell: cell].row];
    respectivePerson.surname = newText;
}

- (IBAction)addItemBtnClick:(id)sender
{
    Person *newPerson = [Person new];

    [_peopleArray addObject: newPerson];

    [self.tableView reloadData];
}

@end

When I click add, I get the following table without any repetitions when I scroll:

enter image description here

pnizzle
  • 6,243
  • 4
  • 52
  • 81
  • I tried to populate cell from datasource in cellForRowAtIndexPath()... but then cell get randomly values and still getting issues. can you suggest me any other option? And please tell me how to alloc init new cell cellForRowAtIndexPath for each item? – Akshay Ambekar Jun 21 '16 at 08:00
  • @AkshayAmbekar have a look at the example i just added. Go ahead and ask if you are not sure about something. – pnizzle Jun 21 '16 at 08:29
  • @AkshayAmbekar see the update. This works fine for me. – pnizzle Jun 22 '16 at 01:29
  • 1
    its working now... But how can I get textFields values?? @pnizzle – Akshay Ambekar Jul 04 '16 at 10:32
  • @AkshayAmbekar please mark this as correct answer if it helped you. This example (above) shows how to get text field values and store them in an person object, a dictionary in your case – pnizzle Jul 04 '16 at 10:36
1

I take it your issue is that after you've added a cell, it doesn't show up in the table. After you make changes in your itemArray dictionary, reload the data for your tableview.

In swift it would look something like this, but I'm sure you'll be able to find the same code in objective c.

yourTableViewOutlet.reloadData()

Whenever you change the dictionary you use to populate/define your tableView data, just reload your data.

Jobs
  • 628
  • 7
  • 27
0

You should call this when you insert or delete UITableViewCell:

**[self.tableView beginUpdates];**
if ([itemsArray count]) {
[itemsArray removeLastObject];
NSIndexPath *index = [NSIndexPath indexPathForRow:0 inSection:0];
AddItemTableViewCell *Cell = (AddItemTableViewCell *)[self.tableView cellForRowAtIndexPath:index];
UITextField * name = (UITextField *)[Cell.contentView viewWithTag:11];
UITextField * Qty = (UITextField *)[Cell.contentView viewWithTag:12];
NSMutableDictionary *item = [NSMutableDictionary new];
[item setObject:name.text forKey:@"item"];
[item setObject:Qty.text forKey:@"quantity"];
[itemsArray addObject:item];

}
[itemsArray addObject:@{@"item":@"",@"quantity":@""}];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

**[self.tableView endUpdates];**
The Mach System
  • 6,703
  • 3
  • 16
  • 20