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;