Skip to content

Commit

Permalink
Housekeeping: Improved readme samples and descriptions. (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmartinezm authored and glennawatson committed Mar 21, 2019
1 parent ee8525d commit fe5af1b
Showing 1 changed file with 52 additions and 83 deletions.
135 changes: 52 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,62 +18,28 @@ Install the following package into you class library and platform-specific proje

## How to use

* For those ViewModels which need validation, implement `ISupportsValidation`
* Add validation rules to the ViewModel
* Bind to the validation rules in the View
* For ViewModels which need validation, implement `ISupportsValidation`.
* Add validation rules to the ViewModel.
* Bind to the validation rules in the View.

## Example

1. Decorate existing ViewModel with `ISupportsValidation`, which has a single member, `ValidationContext`. The ValidationContext contains all of the functionality surrounding the validation of the ViewModel. Most access to the specification of validation rules is performed through extension methods on the ISupportsValidation interface. Then, add validation to the view model.
1. Decorate existing ViewModel with `ISupportsValidation`, which has a single member, `ValidationContext`. The ValidationContext contains all of the functionality surrounding the validation of the ViewModel. Most access to the specification of validation rules is performed through extension methods on the ISupportsValidation interface. Then, add validation to the ViewModel.

```cs
```csharp
public class SampleViewModel : ReactiveObject, ISupportsValidation
{
public SampleViewModel()
{
// Name must be at least 3 chars. The selector is the property
// name and the line below is a single property validator.
// Creates the validation for the Name property
this.ValidationRule(
viewModel => viewModel.Name,
name => !string.IsNullOrWhiteSpace(name),
"You must specify a valid name");

// Age must be between 13 and 100, message includes the silly
// length being passed in, stored in a property of the ViewModel.
AgeRule = this.ValidationRule(
viewModel => viewModel.Age,
age => age >= 13 && age <= 100,
age => $"{age} is a silly age");

var nameAndAgeValid = this
.WhenAnyValue(x => x.Age, x => x.Name, (age, name) => new { Age = age, Name = name })
.Select(x => x.Age > 10 && !string.IsNullOrEmpty(x.Name));

// Create a rule using an IObservable.
// Store in a property of the ViewModel.
ComplexRule = this.ValidationRule(
_ => nameAndAgeValid,
(vm, state) => !state ? "That's a ridiculous name / age combination" : string.Empty);

// Save command is only active when all validators are valid.
Save = ReactiveCommand.CreateFromTask(async unit => { }, this.IsValid());
}

public ValidationContext ValidationContext => new ValidationContext();

public ValidationHelper ComplexRule { get; set; }

public ValidationHelper AgeRule { get; set; }

public ReactiveCommand<Unit, Unit> Save { get; }

private int _age;
public int Age
{
get => _age;
set => this.RaiseAndSetIfChanged(ref _age, value);
}

private string _name;
public string Name
{
Expand All @@ -85,72 +51,75 @@ public class SampleViewModel : ReactiveObject, ISupportsValidation

2. Add validation presentation to the View.

```cs
public class MainActivity : ReactiveAppCompatActivity<SampleViewModel>
```csharp
public class SampleView : ReactiveContentPage<SampleViewModel>
{
public EditText nameEdit { get; set; }

public EditText ageEdit { get; set; }

public TextView nameValidation { get; set; }

public TextView ageValidation { get; set; }
public SampleView()
{
InitializeComponent();

this.WhenActivated((CompositeDisposable disposables) =>
{
this.Bind(ViewModel, vm => vm.Name, view => view.Name.Text)
.DisposeWith(disposables);

// Bind any validations which reference the Name property
// to the text of the NameError UI control
this.BindValidation(ViewModel, vm => vm.Name, view => view.NameError.Text)
.DisposeWith(disposables);
});
}
}
```
Note: `Name` is an Entry and `NameError` is a Label (both are controls from the Xamarin.Forms library).

public TextView validationSummary { get; set; }
## Example with Android extensions

public Button myButton { get; set; }
There are extensions methods for Android specific and its Material design control `TextInputLayout`. These extensions use internally the Error property from this control, allowing you a Material Design and fully native behavior to showing errors.

public TextInputLayout til { get; set; }
To use these extensions you must import `ReactiveUI.Validation.DroidExtensions.Extensions`.

public TextInputEditText tiet { get; set; }
```csharp
using ReactiveUI.Validation.DroidExtensions.Extensions;

protected override void OnCreate(Bundle bundle)
namespace SampleApp.Activities
{
public class SampleActivity : ReactiveAppCompatActivity<SampleViewModel>
{
base.OnCreate(bundle);
public TextInputEditText Name { get; set; }

// Set our View from the "main" layout resource.
SetContentView(Resource.Layout.Main);
WireUpControls();
public TextInputLayout NameLayout { get; set; }

this.BindCommand(ViewModel, vm => vm.Save, v => v.myButton);
this.Bind(ViewModel, vm => vm.Name, v => v.nameEdit.Text);
this.Bind(ViewModel, vm => vm.Age, v => v.ageEdit.Text);
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);

// Bind any validations which reference the name property to the text of the nameValidation control
this.BindValidation(ViewModel, vm => vm.Name, v => v.nameValidation.Text);
// Sets our view from the "main" layout resource
SetContentView (Resource.Layout.Main);

// Bind the validation specified by the AgeRule to the text of the ageValidation control
this.BindValidation(ViewModel, vm => vm.AgeRule, v => v.ageValidation.Text);
WireUpControls();

// bind the summary validation text to the validationSummary control
this.BindValidation(ViewModel, v => v.validationSummary.Text);
this.Bind(ViewModel, vm => vm.Name, view => view.Name.Text);

// bind to an Android TextInputLayout control, utilising the Error property
this.BindValidation(ViewModel, vm => vm.ComplexRule, til);
// Bind any validations which reference the Name property
// to the Error property of the TextInputLayout control
this.BindValidation(ViewModel, vm => vm.Name, NameLayout);
}
}
}
```

## Capabilities

1. Rules can be composed of single or multiple properties along along with more generic Observables.
1. Rules can be composed of single or multiple properties along with more generic Observables.
2. Validation text can encapsulate both valid and invalid states.
3. Binding can occur to either a View or an action.
3. Validation text can reference either the ViewModel or properties which comprise the validation rule e.g. include text entered as part of validation message.
4. Validation text output can be adjusted using custom formatters, not only allowing for single & multiline output but also for platforms like Android it should be possible to achieve richer renderings i.e. Bold/italics.
5. Validation rules in the ViewModel "should" allow for binding of validation results for those environments that support binding (XAML). It should be noted that this however has not been tested.

## Outstanding

1. Binding hasn't been tried at all with Xamarin Forms.
2. An Android specific binding for TextInputLayout has been created, but no platform specific bindings for iOS have been created.
3. Significant usage!
4. Possible additional bit of work related to validationContext & binding.
5. Possible tidyup regarding setup of bindable ValidationHelper in ViewModel.
4. Validation text can reference either the ViewModel or properties which comprise the validation rule e.g. include text entered as part of validation message.
5. Validation text output can be adjusted using custom formatters, not only allowing for single & multiline output but also for platforms like Android it should be possible to achieve richer renderings i.e. Bold/italics.

## How it Works

In essence, its a relatively simple model of the ValidationContext containing a list of IValidationComponent instances. An IValidationComponent provides an observable for ValidationState. Whenever validation state changes (either a transition of validity) or ValidationText changes, then a new value is pushed out.
In essence, it's a relatively simple model of the `ValidationContext` containing a list of `IValidationComponent` instances. An `IValidationComponent` provides an observable for `ValidationState`. Whenever validation state changes (either a transition of validity) or `ValidationText` changes, then a new value is pushed out.

## Feedback

Expand All @@ -159,7 +128,7 @@ Please use [GitHub issues](https://github.com/reactiveui/ReactiveUI.Validation/i
## Authors

* **jcmm33** - *Initial work* - [GitHub profile](https://github.com/jcmm33)
* **Àlex Martínez** - *Repository maintenance* - [GitHub profile](https://github.com/alexmartinezm)
* **Àlex Martínez Morón** - *Repository maintenance* - [GitHub profile](https://github.com/alexmartinezm)

## Copyright and license

Expand Down

0 comments on commit fe5af1b

Please sign in to comment.