csharp/Aaltuj/VxFormGenerator/VxFormGenerator.Core/FormElementBase.cs

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;
        }



    }
}