ASP.NET MVC - Better UX approach to allowing child

2019-07-19 16:52发布

问题:

I have a Contact object that has a number properties, including a child that is a list of Addresses.

public class Contact
{ 
  public int? Id { get; set; }
  public string Name { get; set; }
  public IReadOnlyList<IAddress> Addresses
  {
      [Lazy Load Code to populate and return list]
  } 
  [...]
}

I want to allow the user to edit the addresses without having to edit (or post) the whole Contact object. Currently in the UI I have the addresses listed out with an Edit button next each one:

I'm using the Modal syntax that is part of Bootstrap3, and have hidden DIVs that contain a form and the fields to edit an Address. When the user clicks on edit, a modal window form appears that allows the user to edit the Address. Model Binding and validation work within this form.

It works pretty well but I have a few underlying issues with the implementation. I wanted to use the builtin Validation and Model Binding with the Address objects, but I didn't want to post back the whole object just to edit one address.

So I ended up having to create a for loop that writes out the hidden DIVs calling a Partial View and passing Address as the model:

@for (int i = 0; i < Model.Addresses.Count; i++)
{
        address = (Address)Model.Addresses[i];
        @Html.Partial("_AddressModal", address);
}

The unfortunate side-effect is that the model binding cannot uniquely identify which Address to apply the ModelState to, so Model Binding applies it to all the Address in in the hidden DIVs, instead of the one that was updated. This is because they have the exact same property names.

I've got a work-around that was part of an earlier question. Basically it doesn't write the ModelState unless the object is invalid. For the invalid scenario I don't show the address list which basically hides the problem. Otherwise every edit button would show the same form content.

What I want to know is if there is a better UX approach to allow a user to edit one of the child Addresses in the list?

My goals are to find a better approach using ASP.NET MVC that:

  1. Follow the PRG (Post-Redirect-Get) pattern
  2. Don't redirect to a separate Page/View for editing, which forces the user to navigate back to the contact edit form again
  3. Avoid popups because of the blockers
  4. The solution allows the use Model Binding and Validation for the Address object

回答1:

What you want is :

1 Form for the contact Another form for each address

in your controller you will have an action that expects a contact as a parameter (without addresses) and another action that expects an address.

boilerplate code:

    [HttpPost]
    public RedirectToRouteResult EditAddress(int id, ContactAddressBindingModel address) {
        // ...
    }

    [HttpPost]
    public RedirectToRouteResult EditContact(int id, ContactBindingModel contact)
    {
        // ...
    }

    public class ContactViewModel : ContactBindingModel
    {
        public IReadOnlyList<IAddress> Addresses { // ...}
    }
    public class ContactBindingModel
    {
        public int? Id { get; set; }
        public string Name { get; set; }
    }
    public class ContactAddressBindingModel : IAddress
    {
        public int? Id { get; set; }
        public string City { get; set; }
        public string Country { get; set; }

    }

and in the view :

<form action="EditContact">
<!-- contacts inputs etc -->
</form>

// in razor you can do EditorFor(m => m.Addresses) instead of foreach
// and have partialview, or whatever you like.

@foreach (Model.Addresses) { 
<form action="EditAddress">
<!-- address inputs etc -->
</form>
}