27

Can anyone suggest a good way to develope dynamic forms with ASP.NET MVC?

I have cascading dropdowns on the page (options in the dropdown depends on the value, selected in the previous dropdown).

All the values come from the database.

How can I implement such behavior using ASP.NET MVC?

Of course I'd like to receive all the values in the controller when I submit my form.

Andrei
  • 42,814
  • 35
  • 154
  • 218

6 Answers6

21

You can use FormCollection as a parameter to receive all data that comes from the form:

[HttpPost]
public ActionResult ActionName(FormCollection collection)
{
    //collection["inputName"];
}
Roman Bats
  • 1,775
  • 3
  • 30
  • 40
  • This is by far the easiest solution in my opinion. Why is this answer not as popular as the others? Are there any issues with it that is good to know about? – einord Jun 13 '18 at 12:07
  • 2
    It is IFormCollection – Mosta Jul 28 '21 at 16:19
13

You can do this very easily using my FormFactory library.

By default it reflects against a view model to produce a PropertyVm[] array:

```

var vm = new MyFormViewModel
{
    OperatingSystem = "IOS",
    OperatingSystem_choices = new[]{"IOS", "Android",};
};
Html.PropertiesFor(vm).Render(Html);

```

but you can also create the properties programatically, so you could load settings from a database then create PropertyVm.

This is a snippet from a Linqpad script.

```

//import-package FormFactory
//import-package FormFactory.RazorGenerator


void Main()
{
    var properties = new[]{
        new PropertyVm(typeof(string), "username"){
            DisplayName = "Username",
            NotOptional = true,
        },
        new PropertyVm(typeof(string), "password"){
            DisplayName = "Password",
            NotOptional = true,
            GetCustomAttributes = () => new object[]{ new DataTypeAttribute(DataType.Password) }
        }
    };
    var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper());   

    Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field.
}

```

Theres a demo site with examples of the various features you can set up (e.g. nested collections, autocomplete, datepickers etc.)

mcintyre321
  • 12,996
  • 8
  • 66
  • 103
  • Hi, 1) in this snippet `using (var form = Html.FormForAction((HomeController c, string p0, string p1, bool p2, string p3) => c.SignIn(p0, p1, p2, p3)))` there are 4 vairables, but the action takes 3 variables, 2) How is the submit being performed in the second form, can you expand the documentation a little please, 3) how can I do Lat Long, Fa-Icons? – aggie Aug 22 '15 at 15:00
  • @mcintyre321 can you please explain how can I load settings from a database? – Adnan Niloy May 04 '17 at 08:54
  • 1
    @AdnanNiloy You need to create an intermediate custom Type (e.g. e.g. FieldDefinition) to hold your and store that in the db in a table. Then you hydrate those from your db, and use them to create PropertyVm objects. – mcintyre321 May 05 '17 at 09:45
  • @mcintyre321, Is it possible to do nested models like Country > State > City coming from database? – Maulik Modi Mar 16 '21 at 13:36
  • @maulikmodi using the standard FF controls, you can do nested controls very easily if you are happy to load all the data into the page. To have nested controls driven by lazily fetched data might take a bit of thinking. – mcintyre321 Mar 17 '21 at 15:17
  • @mcintyre321, Our forms are defined in json config files, shape of the data is not known. Is it possible to generate them using JObject containing other JObject or JArray? – Maulik Modi Mar 18 '21 at 10:47
  • @MaulikModi yes - iterate over your JObject and transform it into a List – mcintyre321 Mar 19 '21 at 11:55
11

If you need to have some dynamic fields in your form, the best way for you would be to use some advanced javascript frameworks like Angular, Backbone, Knockout etc.

If you need something more or less simple it is enough for you to use Knockout. For more advanced scenarios I would recommend Angular, but this is my personal preference.

Here is a simple implementation of a dynamic form with Knockout:

var model = {
    users: ko.observableArray(),
    addUser: function() {
        this.users.push({ name: ko.observable() });
    }
};

ko.applyBindings(model);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: users">
    <input type="text" data-bind="value: name" /><br />
</div>
<button data-bind="click: addUser">Add user</button>

<ul data-bind="foreach: users">
    <li data-bind="text: name"></li>
</ul>

Now, what about ASP.NET MVC?

This is more tricky. Perhaps the best and the easiest way would be to use Ajax and post JSON to ASP.NET MVC Action. First of all, you'll need to get a JSON object from your form. With knockout it's very simple:

var json = ko.toJSON(model);

Now, when we know how to get JSON from form, next step is to send your data to an Action. jQuery is perfect for that:

$.ajax({
    type: "POST", 
    url: "@Url.Action("AddUser")",
    data: ko.toJSON(model).users, // Serialize to JSON and take users array
    accept: 'application/json',
    success: function (data) { alert("Done!"); } // Your success callback
});

In our case we basically send an array of strings, thus ASP.NET MVC action should look like that:

[HttpPost]
public JsonResult AddUser(List<string> users)
{
    return Json(data); // return something
}

This is definitely not the only one option of how to implement dynamic forms, but I think it's pretty effective. Hope it helps.

Andrei
  • 42,814
  • 35
  • 154
  • 218
  • 1
    Hi, I am trying to build a dynamic view where the fields and control options are coming from database(e.g. if it is dropdown, is it optional and image uploading etc)...would knockoutjs do the job? I am completely new to it. would appreciate some help or example if possible – Zaki Jan 16 '14 at 18:07
  • 6
    @Zaki, I think, you would like to do dropdown bindings by knockout but make ajax requests to the server by jquery. I suggest you to design knockout page model first, then develop jquery routine. – Andrei Jan 16 '14 at 19:10
  • I tried your code but its not working. Are you missing the User class name on attr: { name: 'Users[' + $index() + '].User'? The Name property is always null on the server. – Onaiggac Jan 08 '15 at 18:26
  • @Onaiggac nice catch! I forgot about second parameter of function ko.applyBindings. Please see an update! Thank you for letting me know! – Andrei Jan 08 '15 at 22:31
  • @AndreiMikhalevich my mistake. You are not missing the User class name but the property name attr: { name: 'Users[' + $index() + '].Name' }. Now its working just fine. I will try with the second parameter. – Onaiggac Jan 09 '15 at 12:47
  • @AndreiMikhalevich with the new code Im still have to add the .Name at the end of attr. Without it I have this result [Error](http://www.pictureshack.us/images/42435_erro.png) and with .Name [OK](http://www.pictureshack.us/images/22513_ok.png) – Onaiggac Jan 09 '15 at 13:03
2

I would create partial views for each option of the dropdown and additional fields. Than controller, that will return such parts of html according to dropdown value:

public class FormFieldsController : Controller
{
    public ActionResult Index(string dropDownOption)
    {
        if(dropDownOption == "Option1")
           return PartialView("PartialForOption1");
       etc.//
    }
}

Then just call it with jquery Ajax and append your current form with result of action, when the value of dropdown changes.

$.ajax("/FormFields/Index",
    {
        async: false,
        data: { dropDownOption: $('#dropDownId').value()},
        success: function(data) {
            if (callback == null) {
                $("#form").append(data);
            } else {
                callback(data);
            }
        },
        error: function() {
            alert('Error');
        },
        type: 'GET',
        timeout: 10000
    }
);
Andrei
  • 42,814
  • 35
  • 154
  • 218
mipe34
  • 5,596
  • 3
  • 26
  • 38
0

Try this http://mvcdynamicforms.codeplex.com/releases/view/43320 it should be helpful

Andrei
  • 42,814
  • 35
  • 154
  • 218
Soner
  • 1,280
  • 3
  • 16
  • 40
  • 1
    http://mvcdynamicforms.codeplex.com/downloads/get/104026 here with code source also – Soner Jun 21 '13 at 07:14
  • 7
    Hey Soner, how can I build model like that: class MyModel {public Form FormData{get;set;}, public string Name{get;set} }, I always get null for form in controller? – Andrei Jun 21 '13 at 08:12
  • 1
    if you ask creating model you are doing it right.But if you ask about something inside
    you must write a name for "form" and in your controller you must call your form name
    – Soner Jun 21 '13 at 08:20
  • Please see an update of my question. I've described my problem there – Andrei Jun 21 '13 at 08:26
  • sorry for not helping more . – Soner Jun 21 '13 at 08:45
0

Take a look at this library:

.NET CRUD with Bootstrap support for creating forms at runtime from a data dictionary. Works on .net 7 or fmk 4.8

https://github.com/JJConsulting/JJMasterData

Lucio Pelinson
  • 430
  • 5
  • 7