VxFormGenerator.Core
FormElementBase.cs
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Rendering;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using VxFormGenerator.Core.Layout;
using VxFormGenerator.Core.Repository;
namespace VxFormGenerator.Core
{
public clast FormElementBase : OwningComponentBase
{
[Inject]
protected IFormGeneratorComponentsRepository Repo { get; set; }
///
/// Bindable property to set the clast
///
public string CssClast { get => string.Join(" ", CssClastes.ToArray()); }
///
/// Setter for the clastes of the form container
///
[Parameter] public List CssClastes { get; set; }
///
/// Will set the 'clast' of the all the controls. Useful when a framework needs to implement a clast for all form elements
///
[Parameter] public List DefaultFieldClastes { get; set; }
///
/// The identifier for the "/> used by the label element
///
[Parameter] public string Id { get; set; }
///
/// Updates the property with the new value
///
[Parameter] public EventCallback ValueChanged { get; set; }
///
/// Get the property that is bound
///
[Parameter] public Expression ValueExpression { get; set; }
///
/// The current Value of the
///
[Parameter] public TFormElement Value { get; set; }
[Parameter] public Layout.VxFormElementDefinition FormColumnDefinition { get; set; }
///
/// Get the instance. This instance will be used to fill out the values inputted by the user
///
[CascadingParameter] EditContext CascadedEditContext { get; set; }
[CascadingParameter] public VxFormLayoutOptions FormLayoutOptions { get; set; }
protected override void OnInitialized()
{
}
///
/// A method that renders the form control based on the
///
///
///
public RenderFragment CreateComponent() => builder =>
{
// Get the mapped control based on the property type
var componentType = Repo.GetComponent(typeof(TFormElement));
// TODO: add the dynamic version for getting a component
if (componentType == null)
return;
// throw new Exception($"No component found for: {propInfoValue.PropertyType.ToString()}");
// Set the found component
var elementType = componentType;
// When the elementType that is rendered is a generic Set the propertyType as the generic type
if (elementType.IsGenericTypeDefinition)
{
Type[] typeArgs = { typeof(TFormElement) };
elementType = elementType.MakeGenericType(typeArgs);
}
/* // Activate the the Type so that the methods can be called
var instance = Activator.CreateInstance(elementType);*/
this.CreateFormComponent(this, FormColumnDefinition.Model, FormColumnDefinition.Name, builder, elementType);
};
///
/// Creates the component that is rendered in the form
///
/// The type of the property
/// The type of the form element, should be based on , like a
/// This
/// The Model instance
/// The property that is being rendered
/// The render tree of this element
/// THe control instance
public void CreateFormComponent(object target,
object dataContext,
string fieldIdentifier, RenderTreeBuilder builder, Type elementType)
{
var treeIndex = 0;
// Create the component based on the mapped Element Type
builder.OpenComponent(treeIndex, elementType);
// Bind the value of the input base the the propery of the model instance
builder.AddAttribute(treeIndex++, nameof(InputBase.Value), Value);
// Create the handler for ValueChanged. This wil update the model instance with the input
builder.AddAttribute(treeIndex++, nameof(InputBase.ValueChanged), ValueChanged);
builder.AddAttribute(treeIndex++, nameof(InputBase.ValueExpression), ValueExpression);
if (FormColumnDefinition.RenderOptions.Placeholder != null)
builder.AddAttribute(treeIndex++, "placeholder", FormColumnDefinition.RenderOptions.Placeholder);
// Set the clast for the the formelement.
builder.AddAttribute(treeIndex++, "clast", GetDefaultFieldClastes(Activator.CreateInstance(elementType) as InputBase));
CheckForInterfaceActions(this, FormColumnDefinition.Model, fieldIdentifier, builder, treeIndex++, elementType);
builder.CloseComponent();
}
private void CheckForInterfaceActions(object target,
object dataContext,
string fieldIdentifier, RenderTreeBuilder builder, int indexBuilder, Type elementType)
{
// Check if the component has the IRenderChildren and renderen them in the form control
if (VxHelpers.TypeImplementsInterface(elementType, typeof(IRenderChildren)))
{
var method = elementType.GetMethod(nameof(IRenderChildren.RenderChildren), BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static);
method.Invoke(null, new object[] { builder, indexBuilder, dataContext, fieldIdentifier });
}
}
///
/// Merges the default control clastes with the 'clast' key
///
/// The property type of the formelement
/// The instance of the component representing the form control
///
private string GetDefaultFieldClastes(InputBase instance)
{
var output = DefaultFieldClastes == null ? "" : string.Join(" ", DefaultFieldClastes);
if (instance == null)
return output;
var AdditionalAttributes = instance.AdditionalAttributes;
if (AdditionalAttributes != null &&
AdditionalAttributes.TryGetValue("clast", out var @clast) &&
!string.IsNullOrEmpty(Convert.ToString(@clast)))
{
return $"{@clast} {output}";
}
return output;
}
}
}