Ant design blazor validation on child components not displaying validation message - validation

I am using Ant design Blazor and trying to create a child component and apply validation as usual from the parent component. Below is my code.
Child component
<AntDesign.FormItem Label="#Label">
<AntDesign.InputNumber Step="Step" Min="Min" #bind-Value="#Amount" OnChange="OnAmountChanged"
TValue="double?" />
</AntDesign.FormItem>
#code {
[Parameter]
public string Label { get; set; }
[Parameter]
public double Step { get; set; }
[Parameter]
public double Min { get; set; } = double.MinValue;
[Parameter]
public double Max { get; set; } = double.MaxValue;
[Parameter]
public string Placeholder { get; set; }
[Parameter]
public double? Amount { get; set; }
[Parameter]
public EventCallback<double?> AmountChanged { get; set; }
private async Task OnAmountChanged(double? value)
{
await AmountChanged.InvokeAsync(value);
}
}
Parent component
<AntDesign.Content>
<AntDesign.Form LabelColSpan="8"
WrapperColSpan="16"
Model="#exchangeRate"
OnFinish="#OnFinish"
OnFinishFailed="#OnFinishFailed">
<Validator>
<FluentValidator TValidator="ExchangeRateValidator" />
</Validator>
<ChildContent>
<AntDesign.FormItem Label="Rate">
<AntDesign.InputNumber Step="0.1" Min="0" #bind-Value="context.Rate" Formatter="RateFormat" />
</AntDesign.FormItem>
<FormItem Label="Date">
<DatePicker TValue="DateTime?" Format="yyyy/MM/dd" #bind-Value="context.Date">
</DatePicker>
</FormItem>
<InputNumberComponent Label="Rate" #bind-Amount="context.Amount"></InputNumberComponent>
<Button Type="primary" HtmlType="submit">Submit</Button>
</ChildContent>
</AntDesign.Form>
</AntDesign.Content>
As can be seen, I am binding the value of Amount to the component directly using #bind-Amount. But, when I click on the Submit button, it triggers validation and displays the validation messages on the first two fields but not on the child component.
Any pointers?

A colleague of mine was able to help with the answer. We had to look into the Ant Design Blazor source for the FormItem to figure out what is happening and get the answer. To get the validation messages, Ant is depending on the validation messages in the EditContext but retrieving them using the Any input control's FieldIdentifier.
The FieldIdentifier is created by Ant using the ValueExpression of the control and not the value. When we set the value, from the child control, the Value taken as the ValueExpression and in turn, when looking for validation messages, it searches for error messages against Value and not the actual model field.
Setting the ValueExpression to a binding expression when binding to the child property fixed the issue.

Related

RequiredAttribute doesn't appear on client-side validation, on derived class

My viewmodel inherits from a class that inherits from an abstract class that has a property with a [Required] attribute, but the rule doesn't appear in the DOM and unobtrusive validation doesn't catch the error.
The display attribute goes through fine, but the validation DOM attributes are not added to the textarea
my view has this:
#model FormPersonView
....
#Html.TextAreaFor(m => m.Description)
#Html.ValidationMessageFor(m => m.Description)
my code has this:
public class FormPersonView : Person
{
//View related stuff
.....
.....
}
public class Person : BasePerson
{
//Person related stuff - validation for these work!
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
public abstract class BasePerson
{
//Base person stuff - validation for this doesn't work!
public string Id { get; set; }
[Required]
[Display("Short description of the person")]
public string Description { get; set; }
}
Why does it work with one level of inheritance but not two? It does work on the server side.
Had exactly this problem. While defining the view, the model comes as a type you defined #model FormPersonView. Data annotations will only work on that specific type, even if you have derived properties from children, their data annotations won't be engaged.
The solution that I came up with in my project was to define editor templates for types I needed data annotations to work properly and then calling #EditorFor on those models. Then and only then were data annotations operating as expected.
Hope this help you.

asp.net mvc3 dynamic validation and entity framework

Thanks for any thoughts.
while I am working my way through some custom validationAttributes, I have come across a problem which should be simple, but has me stumped.
An authorized user will have a UserProfile which includes a key to the site they work in. This site is a record set within a database. 1 field in this site record set is a regular expression which denotes what would be a valid format for a field in a completely separate table. The data entered into this other table will be common to all registered users, but a particular field relates to the ID format used at their institution.
Is there a clean way I can dynamically add a regular expression validator to a property?
Thank you as always.
This is what I came up with, but keen to know if there are better solutions:
Naming conventions are to allow automapper to flatten the model (each StudyCentre has a many to 1 relationship with the RecordSystem (some systems share the patient indexing system)
Mapper.CreateMap<StudyCentre, ParticipantRegistration.StudyCentreViewData>();
As a nested class within the ViewModel for an indidual TrialParticipant
public StudyCentreViewData ViewData { get; set; }
public class StudyCentreViewData
{
public string Abbreviation { get; set; }
public string RecordSystemName { get; set; }
public string RecordSystemHospitalNoRegEx { get; set; }
public string RecordSystemNotationDescription { get; set; }
public IDictionary<string, object> HospitalNoRegEx()
{
return DynamicClientValidation.RegEx(errorMessage:String.Format("{0} must consist of {1}",
RecordSystemName,
RecordSystemNotationDescription),
regExPattern: RecordSystemHospitalNoRegEx);
}
}
The other properties (such as StudyCentre.Abbreviation are for the labels)
The function RegEx is simply:
public static class DynamicClientValidation
{
public static IDictionary<string, object> RegEx(string errorMessage, string regExPattern)
{
var returnVal = new Dictionary<string, object>(3);
returnVal.Add("data-val-regex", errorMessage);
returnVal.Add("data-val-regex-pattern", regExPattern);
returnVal.Add("data-val", "true");
return returnVal;
}
}
The Controller sets up the viewmodel like so:
model.ViewData = Mapper.Map<StudyCentre, ParticipantRegistration.StudyCentreViewData>(_studyCentre.GetCentreByUser(_currentUserName));
and in the view (LabelDetailsfor is a custom helper):
<div class="editor-label">
#Html.LabelDetailsFor(model => model.HospitalID,Model.ViewData.Abbreviation + " ID", Model.ViewData.RecordSystemName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.HospitalID, Model.ViewData.HospitalNoRegEx())
#Html.ValidationMessageFor(model => model.HospitalID)
</div>

MVC 3 / Entity Framework: Binding Collections

I have 2 models, employee and person:
public class Employee
{
[Key]
public int Id { get; set; }
public int? PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
public class Person
{
public IList<PhoneNumber> PhoneNumbers { get; set; }
public int Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public Person()
{
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber()
};
}
}
Editor Template for Phone:
#Html.TextBoxFor(x => x.Number)
#Html.DropDownListFor(m => m, new SelectList(Enum.GetNames(typeof (WebMVC.Core.Common.PhoneType))))
To reduce clutter, I removed the other (non-pertinent) properties.
The difficulty I am having is while in the Employee Create(), I can bind the person FName & LName, I cannot bind the PhoneNumbers collection.
I know about the 2008 Haack blog but I do not think it mirrors this situation.
Does anyone know a solution to bind the person phone numbers collection in the employee's Create()?
I'm not exactly sure if PhoneNumber is a custom class that you created, or one that is built into the framework. But if you're having problems with MVC3 mapping posted data to the Employee class like you specified, you might want to look at creating a custom binding. Keep in mind that if your editor template code is incorrect this wont really matter, so I would take a look at that using fiddler first.
Here are a few good sites to get you started, I found them all on SO at one point.
http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx
http://odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx
http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx
Creating a custom binder gives you complete control over the way that MVC parses your posted model data and populates the object. There are 2 main functions that most people override, CreateModel and BindModel. BindModel is the function you will most likely want to override if this is the way you would like to go.
I don't know what the html from the editor template looks like, but to bind to a collection of custom types it should look something like this:
<input name="[0].Number">
<input name="[0].PhoneType">
<input name="[1].Number">
<input name="[1].PhoneType">
<input name="[2].Number">
<input name="[2].PhoneType">

MVC 3 IList<T> Model Properties NULL on POST

I'll let the code do the talking here, I have something like this:
class Problem
{
public string Title { get; set; }
public string Description { get; set; }
public virtual IList<Symptom> Symptoms { get; set; }
}
class Symptom
{
public string Comments { get; set; }
public virtual Category Category { get; set; }
}
class Category
{
public string Name { get; set; }
}
I have a modal that allows users to add a list of symptoms on my view. Each symptom being added produces an INPUT that looks like this (where N is the index):
<input type="text" name="Symptom[N].Name" value="#Model.Symptom[N].Name">
<input type="text" name="Symptom[N].Category" value="#Model.Symptom[N].Category">
Once I POST the data to my controller, the model contains a valid list of Symptom (if I add 3, my Product.Symptom list has 3 entities) and the [Comments] of each symptom has persisted, but the [Category] property of each is NULL. What am I doing wrong here? I've tried numerous things but I still end up with NULL as the [Category] for each.
I'm using Entity Framework 4.1 Code First with Fluent API developing in MVC 3 using Razor syntax.
Try this:
<input type="text"
name="Symptom[N].Category.Name"
value="#Model.Symptom[N].Category.Name">
What I think is happening is that it's trying to bind a string to a Category which is invalid. If you want to map the text to the Name property on the Category class, you will need to specify it one level deeper.

Custom model validation of dependent properties using Data Annotations

Since now I've used the excellent FluentValidation
library to validate my model classes. In web applications I use it in conjunction with the jquery.validate plugin to perform client side validation as well.
One drawback is that much of the validation logic is repeated on the client side and is no longer centralized at a single place.
For this reason I'm looking for an alternative. There are many examples out there showing the usage of data annotations to perform model validation. It looks very promising.
One thing I couldn't find out is how to validate a property that depends on another property value.
Let's take for example the following model:
public class Event
{
[Required]
public DateTime? StartDate { get; set; }
[Required]
public DateTime? EndDate { get; set; }
}
I would like to ensure that EndDate is greater than StartDate. I could write a custom
validation attribute extending ValidationAttribute in order to perform custom validation logic. Unfortunately I couldn't find a way to obtain the
model instance:
public class CustomValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// value represents the property value on which this attribute is applied
// but how to obtain the object instance to which this property belongs?
return true;
}
}
I found that the CustomValidationAttribute seems to do the job because it has this ValidationContext property that contains the object instance being validated. Unfortunately this attribute has been added only in .NET 4.0. So my question is: can I achieve the same functionality in .NET 3.5 SP1?
UPDATE:
It seems that FluentValidation already supports clientside validation and metadata in ASP.NET MVC 2.
Still it would be good to know though if data annotations could be used to validate dependent properties.
MVC2 comes with a sample "PropertiesMustMatchAttribute" that shows how to get DataAnnotations to work for you and it should work in both .NET 3.5 and .NET 4.0. That sample code looks like this:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
private readonly object _typeId = new object();
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmProperty = confirmProperty;
}
public string ConfirmProperty
{
get;
private set;
}
public string OriginalProperty
{
get;
private set;
}
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, ConfirmProperty);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
return Object.Equals(originalValue, confirmValue);
}
}
When you use that attribute, rather than put it on a property of your model class, you put it on the class itself:
[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public class ChangePasswordModel
{
public string NewPassword { get; set; }
public string ConfirmPassword { get; set; }
}
When "IsValid" gets called on your custom attribute, the whole model instance is passed to it so you can get the dependent property values that way. You could easily follow this pattern to create a date comparison attribute, or even a more general comparison attribute.
Brad Wilson has a good example on his blog showing how to add the client-side portion of the validation as well, though I'm not sure if that example will work in both .NET 3.5 and .NET 4.0.
I had this very problem and recently open sourced my solution:
http://foolproof.codeplex.com/
Foolproof's solution to the example above would be:
public class Event
{
[Required]
public DateTime? StartDate { get; set; }
[Required]
[GreaterThan("StartDate")]
public DateTime? EndDate { get; set; }
}
Instead of the PropertiesMustMatch the CompareAttribute that can be used in MVC3. According to this link http://devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-1:
public class RegisterModel
{
// skipped
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation do not match.")]
public string ConfirmPassword { get; set; }
}
CompareAttribute is a new, very useful validator that is not actually
part of
System.ComponentModel.DataAnnotations,
but has been added to the
System.Web.Mvc DLL by the team. Whilst
not particularly well named (the only
comparison it makes is to check for
equality, so perhaps EqualTo would be
more obvious), it is easy to see from
the usage that this validator checks
that the value of one property equals
the value of another property. You can
see from the code, that the attribute
takes in a string property which is
the name of the other property that
you are comparing. The classic usage
of this type of validator is what we
are using it for here: password
confirmation.
It took a little while since your question was asked, but if you still like metadata (at least sometimes), below there is yet another alternative solution, which allows you provide various logical expressions to the attributes:
[Required]
public DateTime? StartDate { get; set; }
[Required]
[AssertThat("StartDate != null && EndDate > StartDate")]
public DateTime? EndDate { get; set; }
It works for server as well as for client side. More details can be found here.
Because the methods of the DataAnnotations of .NET 3.5 don't allow you to supply the actual object validated or a validation context, you will have to do a bit of trickery to accomplish this. I must admit I'm not familiar with ASP.NET MVC, so I can't say how to do this exactly in conjunction with MCV, but you can try using a thread-static value to pass the argument itself. Here is an example with something that might work.
First create some sort of 'object scope' that allows you to pass objects around without having to pass them through the call stack:
public sealed class ContextScope : IDisposable
{
[ThreadStatic]
private static object currentContext;
public ContextScope(object context)
{
currentContext = context;
}
public static object CurrentContext
{
get { return context; }
}
public void Dispose()
{
currentContext = null;
}
}
Next, create your validator to use the ContextScope:
public class CustomValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
Event e = (Event)ObjectContext.CurrentContext;
// validate event here.
}
}
And last but not least, ensure that the object is past around through the ContextScope:
Event eventToValidate = [....];
using (var scope new ContextScope(eventToValidate))
{
DataAnnotations.Validator.Validate(eventToValidate);
}
Is this useful?

Resources