Fork me on GitHub

FormFactory

The ASP.NET MVC html form builder

View project on GitHub

Reflection form generation

Because you shouldn't have to update your html when you update your object model

Convention based rendering

Specify custom templates for rendering different object types.

Twitter bootstrap support

Styled for bootstrap (by default)

Portable, embeddable

FormFactory.RazorEngine can be used in non ASP projects like console apps, services or WebAPI projects.

Automatically renders:

  • DateTime types as datepickers
  • Data driven select lists
  • Client or server side autocompletes
  • Complex types as multiple inputs
  • Placeholders
  • Sortable lists

FormFactory renders complex object forms automatically. It refects over an object model or method signature, and builds an intermediate model representing the form and properties. These models are then rendered using customisable templates.

FormFactory can build complex nested forms with rich content pickers. By following a few simple code conventions, properties with multiple choices and suggested values can be written in a few lines of code.

Install the library
Nuget install-package FormFactory.AspMvc
or for non ASP MVC projects
Nuget install-package FormFactory.RazorEngine
OR Install the content files (.cshtml, .js, .css)
Nuget install-package FormFactory.Templates
Update your layouts to include
<link href="/Content/FormFactory/FormFactory.css" rel="stylesheet" type="text/css"/>
<script src="/Scripts/FormFactory/FormFactory.js" type="text/javascript"></script>
 
Note: To use FormFactory without installing FormFactory.Templates you must install and configure the EmbeddedResourceVirtualPathProvider

Form for MVC action:

Given this action...

    [HttpPost] public virtual ActionResult SignIn(string email, [DataType(DataType.Password)] string password, string returnUrl)
        { //... } 

..writing this in the view...

 
using (var form = Html.FormForAction((HomeController c, string p0, string p1, bool p2, string p3) => c.SignIn(p0, p1, p2, p3)))
{
    form.Render(); //renders the form
} //.Dispose() closes the form
    

 

...will render this form:

Rendering objects

var me = new Person() { ... set properties ... };

Html.PropertiesFor(me).Render(Html);
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using FormFactory.Attributes;

namespace FormFactory.Example.Models
{
    public class Person
    {
        [DataType(DataType.Date)]
        public DateTime DateOfBirth { get; set; }
        public Person()
        {
        }
        public Person(DateTime dateOfBirth)
        {
            DateOfBirth = dateOfBirth;
            Position = Models.Position.SeniorSubcontractor;
            Enabled = true;
            TopMovies = new List<Movie>()
            {
                new Movie() {Title = "Fight Club"},
                new Movie() {Title = "Bambi"},

            };
            RestrictedMaterials = new[] {"Guns", "Explosives"};
        }

        //readonly property
        public int Age { get { return (int) Math.Floor((DateTime.Now - DateOfBirth).Days/365.25); } }

        //writable property [
        [Required()][StringLength(32, MinimumLength = 8)]
        public string Name { get; set; }

        [Description("Enums are rendered as dropdowns - nullable ones have an empty option")]
        public Position? Position { get; set; }


        public bool Enabled { get; set; }

        public IEnumerable<Hobby> Hobbies { get
        {
            yield return new Hobby("Swimming", 1) ;
            yield return new Hobby("Knitting", 4);

        }}

        public string Gender { get; set; }
        //choices for geneder rendered as a select list
        public IEnumerable<string> Gender_choices() 
        {
            return "male,female,not specified".Split(',');
        }

        [Required]
        [Placeholder("Type to find your location")]
        public string Location { get; set; }
        public IEnumerable<string> Location_suggestions()
        {
            return "USA,UK,Canada".Split(',');
        }

        [Required]
        [DisplayName("Countries (via ajax)")]
        [Placeholder(" via ajax using [SuggestionsUrl(\"...someurl...\")]")]
        [SuggestionsUrl("/home/CountrySuggestions")]
        public string CountryViaAjax { get; set; }

        public ContactMethod ContactMethod { get; set; }
        //you can use objects as choices to create complex nested menus
        public IEnumerable<ContactMethod> ContactMethod_choices() 
        {
            yield return ContactMethod is NoContactMethod ? ContactMethod.Selected() : new NoContactMethod();
            yield return ContactMethod is SocialMedia ? ContactMethod.Selected() : new SocialMedia();
            yield return ContactMethod is PhoneContactMethod ? ContactMethod.Selected() : new PhoneContactMethod();
        }

        //ICollections get rendered as re-orderable lists
        public ICollection<Movie> TopMovies { get; set; }

        //the interface model binder will bind IEnumerable<T> to T[]
        public IEnumerable<string> RestrictedMaterials { get; set; }
        //settable IEnumerable<strings> with choices get rendered as multi-selects.
        public IEnumerable<string> RestrictedMaterials_choices()
        {
            return new[] {"Guns", "Knives", "Explosives", "Nuclear Waste", "Weaponised Viruses"};
        } 
    }


    public class Hobby
    {
        public Hobby(string name, int years)
        {
            Name = name;
            Years = years;
        }

        public string Name { get; private set; }

        public int Years { get; private set; }
    }
}
 
Enums are rendered as dropdowns - nullable ones have an empty option