Converting My Contacts: Step 3a. Restoring input validation
September 02, 2020
This article is a part of a series on converting My Contacts app using Laconic. The start of the series is here.
Step 3a: Restoring Input Validation
When talking about the Step 3 of the conversion I made a promise to restore input validation.
It’s rather simple, really. As always, when leaving the pure world of Laconic we use a bit of middleware in our
App.xaml.cs
:
_binder.UseMiddleware((context, next) =>
{
if (context.Signal is DisplayAlert a)
{
xf.Device.BeginInvokeOnMainThread(() => {
navPage.DisplayAlert(a.Title, a.Message, "OK");
});
}
return next(context);
});
And our Save button calls a validation method instead of sending a signal immediately:
...
new ToolbarItem {
Clicked = () => Proceed(contact)
}
...
static Signal Proceed(Contact contact)
{
if (new [] {contact.LastName, contact.FirstName}.Any(x => string.IsNullOrEmpty(x.Trim())))
return new DisplayAlert("Invalid name!", "A Contact must have both a first and last name.");
var validAddress = new[] {contact.Street, contact.City, contact.State}.All(x => !string.IsNullOrEmpty(x.Trim()))
|| !string.IsNullOrEmpty(contact.PostalCode);
if (!validAddress)
return new DisplayAlert(
"Invalid address!",
"You must enter either a street, city, and state combination, or a postal code.");
return new SaveContact(contact);
}
You might argue that ContactEditor
class breaks SRP: it contains both code for constructing the UI and code for
validating user input. Well, I don’t see it this way. Despite of having class
keyword in its declaration
ContactEditor
doesn’t do any of the OOP stuff. There’s no encapsulated data, and obviously no instance is ever created
(the class is static
). It’s a collection of pure functions. Think of it as a module. This module takes a
contact to be modified, and returns a value that can be either “save this contact to permanent storage” or “more input
from user required” in the form of a signal. The caller then decides what to do with the returned value.
Here is the commit for this step.