Is there a way using annotations to define the "step" attribute? Currently I can only set it by directly setting this in the views
<input asp-for="Quantity" class="form-control" ste="1" />
My model just defines a range currently, which doesn't work with the min/max html attributes:
[Range(0, 9999999)]
public int Quantity { get; set; }
CodePudding user response:
With the hint from a comment, I was able to find and figure this out.
These are the snippets from the code. First an attribute for Step
public class StepAttribute : ValidationAttribute
{
public StepAttribute(double increment)
{
Increment = increment;
}
public StepAttribute(int increment)
{
Increment = increment;
}
public double Increment { get; private set; }
public override bool IsValid(object value)
{
if (int.TryParse(value.ToString(), out int i))
return i > 0;
else if (double.TryParse(value.ToString(), out double d))
return d > 0;
return false;
}
}
Then a tag helper
[HtmlTargetElement("input", Attributes = "asp-for")]
public class InputStepTagHelper : TagHelper
{
public override int Order { get; } = int.MaxValue;
[HtmlAttributeName("asp-for")]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
base.Process(context, output);
if (context.AllAttributes["step"] == null)
{
var increment = GetStepIncrement(For.ModelExplorer.Metadata.ValidatorMetadata);
if (increment > 0)
output.Attributes.Add("step", increment);
}
}
private static double GetStepIncrement(IReadOnlyList<object> validatorMetadata)
{
if (validatorMetadata.Count == 0)
return 0;
for (var i = 0; i < validatorMetadata.Count; i )
if (validatorMetadata[i] is StepAttribute myAttribute && myAttribute.Increment > 0)
return myAttribute.Increment;
return 0;
}
}
I had to add @addTagHelper *, ProjectName
to my _ViewImports
Using the same logic, I added one for the Range to act as a Min/Max to the tag helper
[HtmlTargetElement("input", Attributes = "asp-for")]
public class InputMinMaxTagHelper : TagHelper
{
public override int Order { get; } = int.MaxValue;
[HtmlAttributeName("asp-for")]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
base.Process(context, output);
if (context.AllAttributes["min"] == null)
{
// Attempt to check for a MaxLength annotation
var min = GetMinvalue(For.ModelExplorer.Metadata.ValidatorMetadata);
if (min.HasValue)
output.Attributes.Add("min", min.Value);
}
if (context.AllAttributes["min"] == null)
{
var max = GetMaxvalue(For.ModelExplorer.Metadata.ValidatorMetadata);
if (max.HasValue)
output.Attributes.Add("max", max.Value);
}
}
private static double? GetMinvalue(IReadOnlyList<object> validatorMetadata)
{
if (validatorMetadata.Count == 0)
return null;
for (var i = 0; i < validatorMetadata.Count; i )
if (validatorMetadata[i] is RangeAttribute myAttribute && double.TryParse(myAttribute.Minimum.ToString(), out double d))
return d;
return null;
}
private static double? GetMaxvalue(IReadOnlyList<object> validatorMetadata)
{
if (validatorMetadata.Count == 0)
return null;
for (var i = 0; i < validatorMetadata.Count; i )
if (validatorMetadata[i] is RangeAttribute myAttribute && double.TryParse(myAttribute.Maximum.ToString(), out double d))
return d;
return null;
}
CodePudding user response:
Use the HtmlHelpers and see. Helper methods make it easy to bind to view data or model data especially with anotattions you are using