Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create List<T> from View and POST with form to MVC controller [duplicate]

Background
I'm working on client's website project and I've used MVC to create the site. I've got EF working with a SQLDB to store data.

My WebApp is fitted with a back-office area for managing/adding/updating Items etc.

A particular page in question allows the user to add a new Item to the database by entering data and clicking 'Save' on the form.

The Item has some properties which all get added the DB nicely in a new row.

Item also contains a List<Appointment>s declared against it (I will serialize these and save them in the appropriate column).

The objects look like this (I have removed some properties for brevity):

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Appointment> Appointments { get; set; }
    // Plus some other properties
}

public class Appointment
{
    public string Day { get; set; }
    public string From { get; set; }
    public string To { get; set; }
}

I've set out a ViewModel to use and I'm practising all that usual good-practice stuff. It looks like this:

public class AddItemViewModel
{
    [Required(ErrorMessage = "Please enter an item name")]
    [Display(Name="Item Name")]
    public string Name { get; set; }

    [Display(Name="Appointments")]
    public List<Appointment> Appointments { get; set; }

    ...
    // Other properties in here
    ...
}

I am using the Razor view engine.

I have everything working fine using the @Html.EditorFor(x => x.Property) helper; for all (but one - tell you in a moment) elements on the root object's (Item's) properties.

I can post the ViewModel to the controller and save a new Item, and all that jazz - so all is good there.

Problem
I have a List<Appointment> declared in my ViewModel.

How can I allow the user to add new Appointments to this List<Appointment> from within the page?

I want to assign these to the Item object to be created when the ViewModel is posted - I'll do this in my controller/services etc.

How can I achieve this?

Desired view
I need the user to be able to add Appointments from within the page - up to however many they like, really.

I would like there to be a list of the "created" Appointments in a list (ul or anything similar etc.) in an area on the page.

Underneath that list, I would like some textboxes that are relevant to the Day, From and To properties for the Appointment - with an 'Add' button, which appends it to the list (and clears the textboxes, ideally).

As a bonus, I would also like some sort of "×"-esque "delete" button next to each item, to remove it from the List<Appointment> and the view.

Here is a sample (drawn in MSPaint - old-school tools ftw!) of what I imagine the view to look like:

My desired view design

Things I have tried
I have been digging far and wide, but nothing has come to my rescue, as yet.

  • I have looked at many solutions to do with adding the objects in JavaScript to the page - which does work. Only problem is I can't pick them up in the object that gets posted to the controller.

  • I have also been pointed in the direct of using Ajax to create an Appointment object and insert it into the page, but this didn't seem to get picked up, either.

Your expertise, knowledge and wisdom is much appreciated.

like image 690
Geoff James Avatar asked Nov 09 '22 13:11

Geoff James


1 Answers

  1. To be able to add new Appointments input controls on the UI dynamically, on click of Add button, you can

[code below is from the top of my head, and more like pseudo-code]

a) use jQuery/js to clone a hidden div that you have pre-rendered on the view which contains all the relevant appointment controls.

e.g. this would be a pre-rendered div which will serve as a template

<div style="display:none;" id="appointment-template">
    <input type=text>
</div>

And then the jQuery clone function on click of Add would be something like

var addNewAppointmentRowFromTemplate = function(){
        $("#appointments-list-container").append($("#appointment-template").clone());
    }

OR

b) Get the partial view from the server and append it to the form (again using jQuery $.get / js xhr)

 $.get( "controller/templatDivActionMethodUrl", function( data ) {
      $("#appointments-list-container").append( data );
    });
  1. To be able to send the model with List in Item that is accepted in ActionMethod's Item parameter, you can

a) Dynamically create a json object using jquery/javascript that has the same structure as the server side model (maintainability will be an issue when model is changed).

    var appointmentsJson = [];
    //foreach loop is a pseudo code, can be replaced with $.each()
    foreach (var appointment in $("#appointments-list-container").children()){
            appointmentsJson.push(new {'day' : $(appointment).children("#day").val(),'from' : $(appointment).children("#from").val(),'to' : $(appointment).children("#to").val()})  ;}

    //and then post this json to actionMethod

    $.post("serverController/Actionmethod",{appointments: appointmentsJson});

OR

b) Use the ModelBinder feature that comes with ASP.Net MVC. There's good amount of documentation/tutorials on this our there, a starting point: https://docs.asp.net/en/latest/mvc/models/model-binding.html

like image 119
Saharsh Avatar answered Nov 14 '22 21:11

Saharsh