TTMSFMXListEditor - Limiting or controlling items

Greetings,
This already seems like a great control, and I am looking forward to using it. I read the documentation and have started playing with it.

My number one use would be to add tags or categories to a database record, but I need to limit the added records in many cases to a pre-defined list. Is there an event or way to do so?

Say I have a TStringList of available strings that can be added to a list:
For instance a list of animals: 'Dogs, Cats, Rabbits, Cows, Birds, Fish'
And someone starts typing a new item in my TTMSFMXListEditor, and they type in 'golden retriever', there are at least two things I want to do with this.

1) I want to intercept the item before it is added so I can remove any weird characters and make the first letters upper case and then perhaps add 'Golden Retriever'.

2) If I am limiting it to a list, I would love to show a dialog and ask them?

Are you sure you want to add this to your animal list?
You can also pick from the animals below instead.

[List of Animals]

Any options on how to do this? Thanks,
Scott Lynn

Playing around a little further I am close but not quite there.
I can intercept a tag insert and do what I want to format the tag and even replace or remove a tag that is not in a predefined list using OnItemInsert. For example:

procedure TForm1175.ListEditorItemInsert(Sender: TObject; AItemIndex: Integer);
var
  s : string;
begin
  s := ProperCase(ListEditor.Items[AItemIndex].Text);
  if (slTags.IndexOf(s) = -1) then begin
    // We need to force the user to pick from a list
    PickListDialog.InputSettings.Items.Text := slTags.Text;
    PickListDialog.InstructionText :=
      'You entered a tag that is not in our list.' + #13#10 +
      'Please pick a valid tag:';
    if (PickListDialog.ShowModal = TModalResult.mrOK) then begin
      ListEditor.Items[AItemIndex].Text := PickListDialog.SelectedText;
    end;
  end;
end;

So far so good, but OnItemUpdate triggers on every character stroke while editting an existing tag. Is there an event that triggers when the user is done editting a tag? Or can we allow inserts and deletes but block editting of existing tags?

Thanks,
Scott

Hi, 


The OnEditorHide is called when editing is finished. You could keep track of existing item editing index and process the item in the OnEditorHide event. Below is a sample:

...
  private
    { Private declarations }
    FEditedItemIndex: Integer;
    FEditorShown: Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FEditedItemIndex := -1;
  FEditorShown := False;
end;

procedure TForm1.TMSFMXListEditor1EditorHide(Sender: TObject);
var
  i: Integer;
begin
  i := FEditedItemIndex;
  if (i >= 0) and (i <= TMSFMXListEditor1.Items.Count - 1) and FEditorShown then
  begin
    Log.d('Text changed for item ' + inttostr(i));
    FEditorShown := False;
    FEditedItemIndex := -1;
  end;
end;

procedure TForm1.TMSFMXListEditor1EditorShow(Sender: TObject);
begin
  FEditorShown := True;
end;

procedure TForm1.TMSFMXListEditor1ItemUpdate(Sender: TObject;
  AItemIndex: Integer; var AText: string);
begin
  FEditedItemIndex := AItemIndex;
end;

Blocking editing is done with the ReadOnly flag, but this also blocks inserting and deletion.
You could Hide the editor in the OnEditorShow as soon as the item editing starts on a selected (existing) item:

type
  TTMSFMXListEditorProtected = class(TTMSFMXListEditor);

....

procedure TForm1.TMSFMXListEditor1EditorShow(Sender: TObject);
begin
  if (TMSFMXListEditor1.SelectedItemIndex >= 0) and (TMSFMXListEditor1.SelectedItemIndex <= TMSFMXListEditor1.Items.Count - 1) then
    TTMSFMXListEditorProtected(TMSFMXListEditor1).HideEditor;
end;

Adding new items should then be possible.

We will investigate if we can improve the behavior of the TTMSFMXListEditor

Thank you, that worked great!

I think a Validate event that triggers after an Insert is complete or an Edit is complete would be very useful. I also think it would be useful to have a PickFromItems TStringList where we can list which items are allowed. It would be fantastic to auto-complete from that list and case correct so that a user entering bob jones would match and correct to Bob Jones if that was the entry in the list.

Thanks again!
Scott

Hi,



Thank you for your feedback and suggestions. Note that you can create a custom editor such as TTMSFMXEdit which has a lookup feature.

Could you expand a little bit on that I am able to change the editor in OnEditorCreate but after that ...


I really like the lookup function in TAdvListEditor would be great to have it in  TTMSFMXListEditor

Greetings,

I would be willing to attempt to help here. I have spent some time learning this control and capturing the behavior I want out of it. But I am not familiar with TAdvListEditor. What kind of behavior are you looking for. You asked to expand on "that" but I am not sure which "that" you are asking for.

- Scott

Hi, 


This is some sample code to get you started. The lookup functionality isn't currently built in. We'll investigate if we can add lookup support.



procedure TForm1.DoApplyStyleLookup(Sender: TObject);
var
  b: TFMXObject;
  c: TFMXObject;
begin
  if Sender is TFMXObject then
  begin
    c := Sender as TFMXObject;
    if Sender is TTMSFMXEdit then
    begin
      if c.ChildrenCount > 0 then
        c := c.Children[0];
      b := c.FindStyleResource('background');
      if Assigned(b) and (b is TControl) then
        (b as TControl).Visible := False;
    end;
  end;
end;


procedure TForm1.TMSFMXListEditor1EditorCreate(Sender: TObject;
  var AClass: TTMSFMXCustomListEditorControlClass);
begin
  AClass := TTMSFMXEdit;
end;


procedure TForm1.TMSFMXListEditor1EditorUpdate(Sender: TObject;
  AItemIndex: Integer; var AText: string);
var
  ed: TStyledControl;
begin
  ed := TMSFMXListEditor1.Editor;
  if Assigned(ed) then
  begin
    (ed as TTMSFMXEdit).Text := AText;
    (ed as TTMSFMXEdit).Lookup.Enabled := True;
    (ed as TTMSFMXEdit).Lookup.DisplayList.Add('Item 1');
    (ed as TTMSFMXEdit).Lookup.DisplayList.Add('Item 2');
    (ed as TTMSFMXEdit).Lookup.DisplayList.Add('Item 3');
    (ed as TTMSFMXEdit).OnApplyStyleLookup := DoApplyStyleLookup;
  end;
end;


procedure TForm1.TMSFMXListEditor1ItemUpdate(Sender: TObject;
  AItemIndex: Integer; var AText: string);
var
  ed: TStyledControl;
begin
  ed := TMSFMXListEditor1.Editor;
  if Assigned(ed) then
    AText := (ed as TTMSFMXEdit).Text;
end;


and provides the following result when typing in the editor:

Pieter Scheldeman2017-01-08 09:26:09

Thank you, this is what I've been looking for.