@using System.Linq.Expressions @using System.ComponentModel.DataAnnotations @using System.Reflection @using Microsoft.AspNetCore.Components.Rendering @if (isEditing) {

@TitleString

@CreateEditFormFields()
} else {

Details

@* Create new *@
@CreateCardView()
}

@FormSubmitResult

@code { [Parameter] public object? Data { get; set; } [Parameter] public List IgnoreReflection { get; set; } =new(); [Parameter] public EventCallback OnSubmit { get; set; } [Parameter] public bool isEditing { get; set; } = false; [Parameter] public string TitleString { get; set; } = "Edit your details"; [Parameter] public string ButtonTextString { get; set; } = "Submit"; string _formSubmitResult = ""; private string _spinnerClass = ""; string FormSubmitResult = ""; string PhoneMask { get; set; } = @"((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?"; string EmailMask { get; set; } = @"\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\W*\d(\W*\d){1,14}"; protected override void OnInitialized() { base.OnInitialized(); } protected override void OnParametersSet() { StateHasChanged(); base.OnParametersSet(); } async Task HandleValidSubmit() { //_spinnerClass = "spinner-border spinner-border-sm"; //await Task.Delay(500); var debugString = "Success: "; var myType = Data.GetType(); IList props = new List(myType.GetProperties()); foreach (var prop in props) { var propValue = prop.GetValue(Data, null); // Do something with propValue debugString += $"{prop.Name} = {propValue}\n"; } _formSubmitResult = debugString; _spinnerClass = ""; await OnSubmit.InvokeAsync(Data); isEditing = false; } void HandleInvalidSubmit() { FormSubmitResult = "Please correct all errors"; } void StartEditing() { isEditing = true; } public RenderFragment CreateCardView() => cardViewBuilder => { var mytype = Data.GetType(); var propertyList = mytype.GetProperties(); foreach (var property in propertyList) { if (IgnoreReflection.Contains(property.Name)) { continue; } var displayLabel = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault(); cardViewBuilder.OpenElement(0, "p"); cardViewBuilder.AddContent(1, $"{displayLabel?.Name ?? property.Name}: {property.GetValue(Data)}"); cardViewBuilder.CloseElement(); } }; public RenderFragment CreateEditFormFields() => formLayoutBuilder => { var modelType = Data.GetType(); var properties = modelType.GetProperties(); formLayoutBuilder.OpenComponent(0); formLayoutBuilder.AddAttribute(1, "Model", Data); formLayoutBuilder.AddAttribute(2, "ChildContent", (RenderFragment)((editContext) => (builder) => { int seq = 0; foreach (var property in properties) { if (IgnoreReflection.Contains(property.Name)) continue; var dataTypeAttr = (DataTypeAttribute)property.GetCustomAttributes(typeof(DataTypeAttribute), false).FirstOrDefault(); var displayAttr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault(); var displayName = displayAttr?.Name ?? property.Name; var propertyAccess = Expression.Property(Expression.Constant(Data), property.Name); var lambda = Expression.Lambda( typeof(Func<>).MakeGenericType(property.PropertyType), propertyAccess ); // Label builder.OpenElement(seq++, "div"); builder.AddContent(seq++, displayName); // Input control builder.OpenElement(seq++, "div"); if (property.PropertyType == typeof(string)) { if (dataTypeAttr?.DataType == DataType.MultilineText) { builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Value", (string?)property.GetValue(Data)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, val => property.SetValue(Data, val))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } else { builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Value", (string?)property.GetValue(Data)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, val => property.SetValue(Data, val))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } } else if (property.PropertyType == typeof(int)) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (int?)property.GetValue(Data)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, val => property.SetValue(Data, val))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } else if (property.PropertyType == typeof(double)) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (double?)property.GetValue(Data)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, val => property.SetValue(Data, val))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } else if (property.PropertyType == typeof(DateOnly)) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", (DateOnly?)property.GetValue(Data)); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, val => property.SetValue(Data, val))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } builder.CloseElement(); // end of input wrapper // Validation message builder.OpenComponent(seq++, typeof(ValidationMessage<>).MakeGenericType(property.PropertyType)); builder.AddAttribute(seq++, "For", lambda); builder.CloseComponent(); builder.CloseElement(); // end of outer div } // Submit button builder.OpenElement(seq++, "button"); builder.AddAttribute(seq++, "type", "submit"); builder.AddContent(seq++, ButtonTextString ?? "Submit"); builder.CloseElement(); })); formLayoutBuilder.CloseComponent(); }; private void RenderInputComponent(RenderTreeBuilder builder, ref int seq, PropertyInfo prop, DataTypeAttribute? typeAttr, object? value, LambdaExpression lambda) { var type = typeAttr?.DataType ?? DataType.Text; switch (type) { case DataType.Password: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "type", "password"); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); break; case DataType.PhoneNumber: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.AddAttribute(seq++, "Placeholder", "+11234567890"); builder.CloseComponent(); break; case DataType.Date: builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); break; case DataType.MultilineText: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); break; case DataType.Custom: if (prop.PropertyType == typeof(double)) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } else if (prop.PropertyType == typeof(int)) { builder.OpenComponent>(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); } break; default: builder.OpenComponent(seq++); builder.AddAttribute(seq++, "Value", value); builder.AddAttribute(seq++, "ValueChanged", EventCallback.Factory.Create(this, v => prop.SetValue(Data, v))); builder.AddAttribute(seq++, "ValueExpression", lambda); builder.CloseComponent(); break; } } }