BootstrapForm

in namespace DotVVM.AutoUI.Controls

Usage & Scenarios

Generates a form for the object in the current binding context based on DotVVM Auto UI model metadata.

This control renders HTML and CSS compatible with Bootstrap 5. It contains a handful of properties which can customize it to be compatible with Bootstrap 3 and 4 - see Sample 8.

There are also other versions of this control which produce HTML and CSS classes expected by popular CSS frameworks:

Validation style of CheckBox in Bootstrap 5 and 4

Due to the way how DotVVM CheckBox renders (label wrapped around the input element), you may need to add the following CSS to correctly display validation appearance of this control in the form.

<style>
    .is-invalid.form-check-label, .is-invalid .form-check-label {
        color: #dc3545;
    }
    .is-invalid .form-check-input {
        border-color: #dc3545;
    }
</style>

Sample 1: Basic Form

The DataContext property set on the form or its closest ancestor defines the object for which the form will be auto-generated.

The model metadata or conventions set in Auto UI configuration are used to determine how the editing control for each property will be generated.

<auto:BootstrapForm DataContext="{value: Customer}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }
}

Sample 2: Groups of properties

To create more complex layouts or generate editors just for some properties, you can use the GroupName property to tell the control which group of properties shall be considered.

The property can be assigned to a specific group using the Display attribute:

[Display(..., GroupName = "basic")]
public string FirstName { get; set; }
<div class="row">
    <div class="col">
        <auto:BootstrapForm DataContext="{value: Customer}" GroupName="BasicInfo" />
    </div>
    <div class="col">
        <auto:BootstrapForm DataContext="{value: Customer}" GroupName="ContactInfo" />
    </div>
</div>
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name", GroupName = "BasicInfo")]
    public string Name { get; set; }

    [Display(Name = "Is company", GroupName = "BasicInfo")]
    public bool IsCompany { get; set; }


    [Display(Name = "E-mail address", GroupName = "ContactInfo")]
    public string Email { get; set; }

    [Display(Name = "Phone number", GroupName = "ContactInfo")]
    public string Phone { get; set; } 
}

Sample 3: Explicit property listing

If you prefer explicit listing of the properties, you can use the IncludeProperties and ExcludeProperties properties to specify which properties shall be generated.

<div class="row">
    <div class="col">
        <auto:BootstrapForm DataContext="{value: Customer}" IncludeProperties="Name,IsCompany" />
    </div>
    <div class="col">
        <auto:BootstrapForm DataContext="{value: Customer}" ExcludeProperties="Name,IsCompany" />
    </div>
</div>
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }


    [Display(Name = "E-mail address")]
    public string Email { get; set; }

    [Display(Name = "Phone number")]
    public string Phone { get; set; } 
}

Sample 4: Include properties based on view

Sometimes you want to reuse the same model object in multiple contexts, a.k.a. "views".

You can decorate the properties with the Visible attribute to define in which views they shall appear.

// will be shown only when ViewName == "List"
[Visible(ViewNames = "List")]
public string CountryName { get; set; }
 
// will be shown only when ViewName == "Insert" || ViewName == "Edit"
[Visible(ViewNames = "Insert | Edit")]
public int CountryId { get; set; }
 
// will be shown only when ViewName != "Insert" && ViewName != "Edit"
[Visible(ViewNames = "!Insert & !Edit")]
public int UserId { get; set; }

The ViewName property specifies the view name for the current context. That's why only the editor for the CountryId property is displayed in the sample.

<auto:BootstrapForm DataContext="{value: Customer}" ViewName="Edit" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();
}

public class CustomerModel 
{
    [Visible(ViewNames = "List")]
    public string CountryName { get; set; }

    [Visible(ViewNames = "Insert | Edit")]
    public int CountryId { get; set; }
}

Sample 5: Adding extra properties

You can include additional properties to those coming from the current binding context by using the Property-* property group.

If a property with the same name is present in the current binding context, it will be overriden by this settings.

<auto:BootstrapForm DataContext="{value: Customer}" 
                    Property-AgreeWithConditions="{value: _root.AgreeWithConditions}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();

    public bool AgreeWithConditions { get; set; }
}

public class CustomerModel 
{
    [Display(Name = "Person or company name")]
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }
}

Sample 6: Responding to changes and enabling properties

You can use the Changed-* and Enabled-* property groups to specify commands triggered when the user changes the value, and to specify whether the field is editable.

There is also Visible-* property group which guides the field visibility, and Label-* property group which can override property labels.

<auto:BootstrapForm DataContext="{value: Customer}" 
                    Enabled-CompanyNumber="{value: IsCompany}" 
                    Changed-CompanyNumber="{command: _root.LookupCompanyAddress()}" 
                    Visible-CountryName="{value: IsInternational}" 
                    Label-Name="{value: IsCompany ? 'Company name' : 'Person name'}" />
public class ViewModel : DotvvmViewModelBase
{
    public CustomerModel Customer { get; set; } = new();

    public void LookupCompanyAddress() 
    {
        // TODO
    }
}

public class CustomerModel 
{
    public string Name { get; set; }

    [Display(Name = "Is company")]
    public bool IsCompany { get; set; }

    [Display(Name = "Company number")]
    public string CompanyNumber { get; set; }

    [Display(Name = "International customer")]
    public bool IsInternational { get; set; }

    [Display(Name = "Country")]
    public string CountryName { get; set; }
}

Sample 7: Overriding generated templates

You can use the EditorTemplate-* property group to override the generated editor control with your own content.

If you need to override the entire form field (including the label element), use the FieldTemplate-* instead.

In our sample, we are providing file upload and image preview experience for the ImageUrl, and selection of values from a viewmodel collection for the Type property.

You can use the Selector attribute to auto-generate selection controls.

<auto:BootstrapForm DataContext="{value: Image}">
    <EditorTemplate-Type>
        <dot:ComboBox DataSource="{value: _root.Types}" 
                      SelectedValue="{value: Type}" 
                      class="form-select"/>
    </EditorTemplate-Type>
    <FieldTemplate-ImageUrl>
        <!-- Please note that you are responsible to render the structual elements produced by the BootstrapForm control -->
        <div>
            <img src="{value: ImageUrl}" class="img-responsive" />

            <dot:FileUpload UploadedFiles="{value: _root.ImageUpload}" 
                            UploadCompleted="{command: _root.ProcessImage()}" 
                            class="form-control" />
        </div>
    </FieldTemplate-ImageUrl>
</auto:BootstrapForm>
public class ViewModel : DotvvmViewModelBase
{
    public ImageModel Image { get; set; } = new();

    public UploadedFilesCollection ImageUpload { get; set; } = new();

    public string[] Types => new[] { "Small", "Large" };

    public void ProcessImage() 
    {
        // TODO
    }
}

public class ImageModel 
{
    public string ImageUrl { get; set; }

    public string Type { get; set; }
}

Properties

Name Type Description Notes Default Value
property icon ExcludeProperties String[] The specified properties will not be included in this form.
attribute
inner element
static value
bindable
default
[]
property icon FormCheckCssClass String Gets or sets the CSS class that will be applied to the rendered div element when the form group contains checkboxes or radio buttons.
attribute
inner element
static value
bindable
default
form-check
property icon FormCheckInputCssClass String Gets or sets the CSS class that will be applied on the input element of the CheckBox or RadioButton controls inside the form group.
attribute
inner element
static value
bindable
default
form-check-input
property icon FormCheckLabelCssClass String Gets or sets the CSS class that will be applied on the label element of the CheckBox or RadioButton controls inside the form group.
attribute
inner element
static value
bindable
default
form-check-label
property icon FormControlCssClass String Gets or sets the CSS class that will be applied to the rendered control elements (TextBox and other input types, except for select, checkbox and radios).
attribute
inner element
static value
bindable
default
form-control
property icon FormGroupCssClass String Gets or sets the CSS class that will be applied to the root div element. Set this to 'form-group' if you are using Bootstrap 3 and 4.
attribute
inner element
static value
bindable
default
mb-4
property icon FormSelectCssClass String Gets or sets the CSS class that will be applied to the rendered select elements. Set this to 'form-control' if you are using Bootstrap 3 and 4.
attribute
inner element
static value
bindable
default
form-select
property icon GroupName String Gets or sets the group of fields that should be rendered. If not set, fields from all groups will be rendered.
attribute
inner element
static value
bindable
default
null
property icon IncludeProperties String[] Only the specified properties will be included in this form. Using ViewName, GroupName or ExcludedProperties at the same time as IncludedProperties does not make sense. The properties will be listed in the exact order defined in this property.
attribute
inner element
static value
bindable
default
null
property icon LabelCssClass String Gets or sets the CSS class that will be applied to the rendered label element.
attribute
inner element
static value
bindable
default
control-label
property icon RequiresFormCheckCssClass Boolean Indicates that when the AutoEditor control is used inside BootstrapForm, it should be wrapped in a div with a 'form-check' CSS class. This attached property is intended to be used when implementing custom FormEditorProviders.
attribute
inner element
static value
bindable
default
False
property icon RequiresFormControlCssClass Boolean Indicates that when the AutoEditor control is used inside BootstrapForm, it should be wrapped in a div with a 'form-control' CSS class. This attached property is intended to be used when implementing custom FormEditorProviders.
attribute
inner element
static value
bindable
default
False
property icon RequiresFormSelectCssClass Boolean Indicates that when the AutoEditor control is used inside BootstrapForm, it should be wrapped in a div with a 'form-select' CSS class. This attached property is intended to be used when implementing custom FormEditorProviders.
attribute
inner element
static value
bindable
default
False
property icon ViewName String Gets or sets the view name (e.g. Insert, Edit, ReadOnly). Some fields may have different metadata for each view.
attribute
inner element
static value
bindable
default
null

HTML produced by the control

<div class="mb-4">
  <label class="control-label autoui-required" for="Name__input">Person or company name</label>
  <div>
    <input class="form-control" type="text" required id="Name__input" ... />
  </div>
</div>
<div class="mb-4">
  <div class="form-check">
    <label id="IsCompany__input" class="form-check-label">
      <input type="checkbox" class="form-check-input" ... >
      <span>Is company</span>
    </label>
  </div>
</div>

Bootstrap 3 and 4 compatibility

The BootstrapForm control contains several properties which can be set to configure CSS class names. The default values of these properties are suited to work with Bootstrap 5.

For earlier versions, you may configure the values as follows:

Property Bootstrap 4 Bootstrap 3
FormGroupCssClass "form-group" "form-group"
LabelCssClass "" ""
FormControlCssClass "form-control" "form-control"
FormSelectCssClass "form-control" "form-control"
FormCheckCssClass "form-group form-check" "checkbox"
FormCheckLabelCssClass "form-check-label" ""
FormCheckInputCssClass "form-check-input" ""
WrapControlInDiv false true
Validator.InvalidCssClassProperty "is-invalid" "has-error"

You can set these properties globally for your application using server-side styles in DotvvmStartup.cs:

// for Bootstrap 3
config.Styles.Register<BootstrapForm>()
    .SetProperty(c => c.FormGroupCssClass, "form-group")
    .SetProperty(c => c.LabelCssClass, "")
    .SetProperty(c => c.FormControlCssClass, "form-control")
    .SetProperty(c => c.FormSelectCssClass, "form-control")
    .SetProperty(c => c.FormCheckCssClass, "checkbox")
    .SetProperty(c => c.FormCheckLabelCssClass, "")
    .SetProperty(c => c.FormCheckInputCssClass, "")
    .SetProperty(c => c.WrapControlInDiv, true)
    .SetDotvvmProperty(Validator.InvalidCssClassProperty, "has-error");
    
// for Bootstrap 4
config.Styles.Register<BootstrapForm>()
    .SetProperty(c => c.FormGroupCssClass, "form-group")
    .SetProperty(c => c.LabelCssClass, "")
    .SetProperty(c => c.FormControlCssClass, "form-control")
    .SetProperty(c => c.FormSelectCssClass, "form-control")
    .SetProperty(c => c.FormCheckCssClass, "form-check")
    .SetProperty(c => c.FormCheckLabelCssClass, "form-check-label")
    .SetProperty(c => c.FormCheckInputCssClass, "form-check-input")
    .SetDotvvmProperty(Validator.InvalidCssClassProperty, "is-invalid");