Editing Tasks

Your sample application now works pretty well as a read-only application, but it's time to start adding some features to add and change data. You are going to start by adding the ability to edit existing tasks.

Edit Task Form

Add a new form to the project and name it EditForm.

Add the following controls:

  • TEdit , name: editTitle
  • TDateTimePicker, name: dateDueDate
  • TComboBox, name: comboPriority
  • TMemo, name: editDescription
  • TCheckBox, name: checkIsCompleted
  • TButton, name: btnOK with ModalResult set to OK
  • TButton, name: ***btnCancel with ModalResult set to Cancel

Add labels and place controls as shown in the screenshot:

Edit Tasks Form

Clone The Properties Table

Create a new TDAMemDataTable instance (found in the RemObjects Data Abstract section of the Tool Palette) in the ClientDataModule and set it up with the following properties:

  • Name: tbl_cloneProperties
  • CloneSource: tbl_Priorities
  • CloneAutoOpen: true

This table clones the tbl_Priorities table, so the cloned table can be looped without changing position in tbl_Priorities.

Edit Form Code

Back in fEditForm.pas, implement the event for btnOnClick and FormShow.

//fEditForm.pas
unit fEditForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, DB;

type
  TEditForm = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    editTitle: TEdit;
    dateDueDate: TDateTimePicker;
    comboPriority: TComboBox;
    editDescription: TMemo;
    checkIsCompleted: TCheckBox;
    btnOK: TButton;
    btnCancel: TButton;
    procedure FormShow(Sender: TObject);
    procedure btnOKClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  EditForm: TEditForm;


implementation

{$R *.dfm}

uses
  fClientDataModule, uDAMemDataTable;



procedure TEditForm.btnOKClick(Sender: TObject);
var
  l_tbl_tasks : TDAMemDataTable;
begin
  l_tbl_tasks := ClientDataModule.tbl_Tasks;
  l_tbl_tasks.FieldByName('Task').AsWideString := editTitle.Text;
  l_tbl_tasks.FieldByName('DueDate').AsDateTime := dateDueDate.Date;
  l_tbl_tasks.FieldByName('Priority').AsLargeInt := Integer(comboPriority.Items.Objects[comboPriority.ItemIndex]);
  l_tbl_tasks.FieldByName('Details').AsWideString := editDescription.Text;
  if checkIsCompleted.Checked then
    l_tbl_tasks.FieldByName('Done').AsLargeInt := 1
  else
    l_tbl_tasks.FieldByName('Done').AsLargeInt := 0;
end;

procedure TEditForm.FormShow(Sender: TObject);
var
  l_tbl_tasks, l_tbl_priority: TDAMemDataTable;
  i: integer;
begin
  //set up comboPriority
  comboPriority.Items.Clear;
  l_tbl_priority := ClientDataModule.tbl_clonePriorities;
  l_tbl_priority.Open;
  l_tbl_priority.First;
  while not l_tbl_priority.EOF do begin
    comboPriority.Items.AddObject(
      l_tbl_priority.FieldByName('Name').AsWideString,
      Pointer(l_tbl_priority.FieldByName('Id').AsLargeInt));
    l_tbl_priority.Next;
  end;

  //reference the tasks table
  l_tbl_tasks := ClientDataModule.tbl_Tasks;

  //if the tasks table is in edit mode, get the details from
  //the current record and set up the edit controls
  if l_tbl_tasks.State = dsEdit then begin
    editTitle.Text := l_tbl_tasks.FieldByName('Task').AsWideString;
    dateDueDate.Date := l_tbl_tasks.FieldByName('DueDate').AsDateTime;
    for i := 0 to comboPriority.Items.Count-1 do
      if Integer(comboPriority.Items.Objects[i]) = l_tbl_tasks.FieldByName('Priority').AsLargeInt then begin
        comboPriority.ItemIndex := i;
        Break;
      end;
    editDescription.Text := l_tbl_tasks.FieldByName('Details').AsWideString;
    checkIsCompleted.Checked := l_tbl_tasks.FieldByName('Done').AsLargeInt = 1;
  end
  else begin
    //no record to edit yet, so initialize the date and priority
    dateDueDate.Date := Date;
    comboPriority.ItemIndex := 0;
  end;
end;

end.

Spend a few moments looking at the code. It is hopefully pretty straightforward. The FormShow event checks whether tbl_tasks is in an edit state and whether it populates the controls with the current values. If tbl_tasks is not in an edit state, the controls are simply initialized. When btnOK is clicked, the values are simply copied from the controls into the current record of tbl_tasks

The DataModule

Add Forms, UITypes and fEditForm units into the uses section of the fClientDataModule:

uses
  Forms, UITypes,
  fLogOnForm, fEditForm;

Add a public method, editTask, to the DataModule. This method checks whether tbl_tasks is on a valid record. If it is, put tbl_tasks into edit mode and create an instance of EditForm.

When the EditForm closes, either Post the changes to tbl_tasks or cancel them.

procedure TClientDataModule.EditTask;
var
  leditform: TEditForm;
begin
  if tbl_Tasks.BOF and tbl_Tasks.EOF then begin
    Exit;
  end;

  leditform := TEditForm.Create(Application);
  try
    leditform.Caption := 'Edit Task';
    tbl_Tasks.Edit;
    if leditform.ShowModal = mrOk then
      tbl_Tasks.Post
    else
      tbl_Tasks.Cancel;
  finally
    leditform.Release;
  end;
end;

The ClientForm

Add another TButton to the main form, call it btnEdit and set its caption to Edit.

Add Edit Button

In btnEdit's onClick, call the editTask method of the DataModule.

procedure TClientForm.btnEditClick(Sender: TObject);
begin
  ClientDataModule.editTask();
end;

With that done, your sample app should now be able to edit tasks.

Edit Task