Q: I am trying to use the ValidationFrame
to validate and edit entries in a protoListPicker
. When I edit certains slots I get an error that a path failed. All the failures occur on items that are nested frames in my soup entry. What is going on?
A: The built-in validation mechanism is not designed to deal with nested soup information. In general, you gain better flexibility by not using a validationFrame
in your pickerDef, even if you have no nested entries. Instead, you can provide your own validation mechanism and editors:
Define a Validate
method in your picker definition
Define an OpenEditor
method in your picker definition
Draw a layout for each editor you require
pickerDef.Validate(nameRef, pathArray)
nameRef
- nameRef to validate
pathArray
- array of paths to validate in the nameRef
returns an array of paths that failed, or an empty array
Validate each path in pathArray
in the given nameRef. Accumulate a list of paths that are not valid and return them.
The following example assumes that pickerDef.ValidateName
and pickerDef.ValidatePager
have been implemented:
pickerDef.Validate := func(nameRef, pathArray)
begin
// keep track of any paths that fail
local failedPaths := [];
foreach index, path in pathArray do
begin
if path = 'name then
begin
// check if name validation fails
if NOT :ValidateName(nameRef) then
// if so, add it to array of failures
AddArraySlot(failedPaths, path);
end;
else begin
if NOT :ValidatePager(nameRef) then
AddArraySlot(failedPaths, path);
end;
end;
// return failed paths or empty array
failedPaths;
end;
pickerDef.OpenEditor(tapInfo, context, why)
The arguments and return value are as per OpenDefaultEditor
. However, you need to use this instead of DefaultOpenEditor
.
pickerDef.OpenEditor := func(tapInfo, context, why)
begin
local valid = :Validate(tapInfo.nameRef, tapInfo.editPaths) ;
if (Length(valid) > 0) then
// if not valid, open the editor
// NOTE: returns the edit slip that is opened
GetLayout("editor.t"):new(tapInfo.nameRef,
tapInfo.editPaths, why, self, 'EditDone, context);
else
begin
// the item is valid, so just toggle the selection
context:Tapped('toggle);
nil; // Return <nil>.
end;..
end;
The example above assumes that the layout "editor.t" has a New
method that will open the editor and return the associated View.
The editor can be designed to fit your data. However, we suggest that you use a protoFloatNGo
that is a child of the root view created with the BuildContext
function. You are also likely to need a callback to the pickderDef so it can appropriately update the edited or new item. Finally, your editor will need to update your data soup uing an "Xmit" soup method so that the listPicker will update.
In the OpenEditor
example above, the last three arguments are used by the editor to send a callback to the pickerDef from the viewQuitScript
. The design of the callback function is up to you, here is an example:
pickerDef.EditDone := func(nameRef, context)
begin
local valid = :Validate(tapInfo.nameRef, tapInfo.editPaths) ;
if (Length(valid) > 0) then
begin
// Something failed. Try and revert back to original
if NOT :ValidatePager(nameRef) AND
self.('[pathExpr: savedPagerValue, nameRef]) = nameRef then
nameRef.pager := savedPagerValue.pager;
context:Tapped(nil); // Remove the checkmark
end;
else
// The nameRef is valid, so select it.
context:Tapped('select);
// Clear the saved value for next time.
savedPagerValue := nil;
end;