Form ▸ Customize Fields at Runtime

The Form component allows you to add/remove items and specify item visibility at runtime. The Form only updates the affected items and does not re-render the entire form.

In this demo, the "Show Address" checkbox specifies the visibility of address-related fields. Review the component's code to see how to set the "HomeAddress" group's visible attribute.

Click the "Add phone" button to add a new phone editor. This action adds a new item to the items array of the "phones" group. Each phone editor contains a button that deletes it from the items array and the Form.

Personal details

@using DevExtreme.MVC.Demos.ViewModels
@model DynamicFormViewModel

<div class="long-title"><h3>Personal details</h3></div>
<div id="form-container">
    @(Html.DevExtreme().Form<DynamicFormViewModel>()
        .ID("form")
        .ColCount(2)
        .Items(groups => {
            groups.AddGroup()
                .Items(leftGroup => {
                    leftGroup.AddGroup()
                        .Caption("Personal Data")
                        .Items(items => {
                            items.AddSimpleFor(m => m.FirstName);
                            items.AddSimpleFor(m => m.LastName);
                            items.AddSimple()
                                .Label(l => l.Text(""))
                                .Editor(e =>
                                    e.CheckBox()
                                        .OnValueChanged("onCheckBoxValueChanged")
                                        .Text("Show Address")
                                        .Value(true)
                                );
                        });

                    leftGroup.AddGroup()
                        .Items(addressGroup => {
                            addressGroup.AddGroup()
                            .Name("HomeAddress")
                            .Caption("Home Address")
                            .Items(items => {
                                items.AddSimpleFor(m => m.Address);
                                items.AddSimpleFor(m => m.City);
                            });
                        });
                });

            groups.AddGroup()
                .Name("phones-container")
                .Caption("Phones")
                .Items(rightGroup => {
                    rightGroup.AddGroup()
                        .Name("phones")
                        .Items(items => {
                            items.AddSimpleFor(m => m.Phones[0])
                                .Label(l => l.Text("Phone 1"))
                                .CssClass("phone-editor")
                                .Editor(e =>
                                    e.TextBox()
                                        .Mask("+1 (X00) 000-0000")
                                        .InputAttr("aria-label", "Mask")
                                        .MaskRules(new { X = new JS("/[01-9]/") })
                                        .Buttons(b =>
                                            b.Add().Name("Trash")
                                            .Location(TextEditorButtonLocation.After)
                                            .Widget(w =>
                                                w.Button()
                                                    .StylingMode(ButtonStylingMode.Text)
                                                    .Icon("trash")
                                                    .OnClick("function(e) {onTrashButtonClick(0)}")
                                            )
                                        )
                                    );

                            items.AddSimpleFor(m => m.Phones[1])
                                .Label(l => l.Text("Phone 2"))
                                .CssClass("phone-editor")
                                .Editor(e =>
                                    e.TextBox()
                                        .Mask("+1 (X00) 000-0000")
                                        .InputAttr("aria-label", "Mask")
                                        .MaskRules(new { X = new JS("/[01-9]/") })
                                        .Buttons(b =>
                                            b.Add().Name("Trash")
                                                .Location(TextEditorButtonLocation.After)
                                                .Widget(w =>
                                                    w.Button()
                                                        .StylingMode(ButtonStylingMode.Text)
                                                        .Icon("trash")
                                                        .OnClick("function(e) {onTrashButtonClick(1)}")
                                                )
                                        )
                                    );
                    });

                    rightGroup.AddGroup()
                        .Items(items => {
                            items.AddButton()
                                .HorizontalAlignment(HorizontalAlignment.Left)
                                .CssClass("add-phone-button")
                                .ButtonOptions(b =>
                                    b.Icon("add")
                                        .Text("Add phone")
                                        .OnClick("onAddButtonClick")
                                );
                        });
                });
        })
        .OnInitialized("onFormInitialized")
        .OnContentReady("onFormReady")
        .FormData(Model)
    )
</div>
<script>
    var form,
        employee,
        isFirstLoad = true;

    function onFormInitialized(e) {
        form = e.component;
    }

    function onFormReady(e) {
        if (isFirstLoad) {
            employee = e.component.option("formData");
            isFirstLoad = false;
        }
    }

    function onCheckBoxValueChanged(e) {
        form.itemOption("HomeAddress", "visible", e.value);
    }

    function onAddButtonClick() {
        employee.Phones.push("");
        form.itemOption("phones-container.phones", "items", getPhonesOptions(employee.Phones));
    }

    function onTrashButtonClick(index) {
        employee.Phones.splice(index, 1);
        form.itemOption("phones-container.phones", "items", getPhonesOptions(employee.Phones));
    }

    function getPhonesOptions(phones) {
        var options = [];
        for (var i = 0; i < phones.length; i++) {
            options.push(generateNewPhoneOptions(i));
        }
        return options;
    }

    function generateNewPhoneOptions(index) {
        return {
            dataField: "Phones[" + index + "]",
            editorType: "dxTextBox",
            cssClass: "phone-editor",
            label: {
                text: "Phone " + (index + 1)
            },
            editorOptions: {
                mask: "+1 (X00) 000-0000",
                maskRules: { "X": /[01-9]/ },
                buttons: [{
                    name: "trash",
                    location: "after",
                    options: {
                        stylingMode: "text",
                        icon: "trash",
                        onClick: function () {
                            onTrashButtonClick(index);
                        }
                    }
                }]
            }
        }
    }
</script>
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DevExtreme.MVC.Demos.Models.SampleData;
using DevExtreme.MVC.Demos.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Web.Mvc;

namespace DevExtreme.MVC.Demos.Controllers {
    public class FormController : Controller {

        public ActionResult UpdateItemsDynamically() {
            return View(new DynamicFormViewModel {
                FirstName = "John",
                LastName = "Heart",
                Address = "351 S Hill St., Los Angeles, CA",
                City = "Atlanta",
                Phones = new List<string> { "8005552797", "8005953232" }
            });
        }

    }
}
#form-container {
    margin: 10px 10px 30px;
}

.long-title h3 {
    font-family: 'Segoe UI Light', 'Helvetica Neue Light', 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana;
    font-weight: 200;
    font-size: 28px;
    text-align: center;
    margin-bottom: 20px;
}

.add-phone-button {
    margin-top: 10px;
}