ViewModel with complex property
Asked Answered
S

3

6

I am unsure how I can get this to work. I dont know how I can create [Display(Name = "XXXX")] for my Customer properties on this ViewModel:

public class CreateAccountViewModel
{
    [Required]
    public Customer Customer { get; set; }

    [Required]
    [Display(Name = "Username")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    public string ConfirmPassword { get; set; }
}

Should I create a ViewModel for Customer and reference that instead of the Customer object? And then create Display() for all of the properties?

If so, will the mapping work on submit?

I use this as follows (snippet):

<div class="form-group">
    @Html.LabelFor(m => m.Customer.CompanyName, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.Customer.CompanyName, new { @class = "form-control" })
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(m => m.Customer.CVR, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.TextBoxFor(m => m.Customer.CVR, new { @class = "form-control" })
    </div>
</div>

And the "CompanyName" I wish to change to something more nice like "Company name". :-)

Salome answered 24/12, 2013 at 12:25 Comment(0)
L
4

As usual if I need to display some complex model with such sub objects - I create another model for this object, specify attributes in new model. And then specify this model instead of Customer property.

@Html.LabelFor(m => m.Customer.CompanyName, new { @class = "col-md-2 control-label" })

Should work fine for sub models, if it has Display attribute.

Another way is to specify these attributes under your domain classes, but as for me - i don't like to dirty domain objects with UI attributes

Lakh answered 24/12, 2013 at 12:50 Comment(3)
So, create a CustomerViewModel and use that instead of the Customer object?Salome
Yes, I usually do it in that way. And if I need to display Customer object on another object, then I use the same model CustomerModel object.Lakh
+1... whilst many times the database POCO is analogous to the display version, you quickly realise that you need a ViewModel for that POCO that differs because displaying something requires fundamental differences from the one you throw in to the database.Compulsion
B
0

Yo can use this Structure:

[DisplayName("YourName")]
public string UserName { get; set; }

and in your view:

@Html.DisplayNameFor(m => m.Customer.CompanyName, new { @class = "col-md-2 control-label" }))
Banditry answered 24/12, 2013 at 12:36 Comment(1)
Yes, but how do I map that for the ´Customer´ object properties?Salome
S
0

Okay, I have done a different approach. I am not sure if this is any more elegant. Upon my research I came across AutoMapper and have done this. If anyone has a better solution to my problem, please let me know. :-)

public static class AutoMapperWebConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.AddProfile(new CustomerMapper());
            cfg.AddProfile(new CustomerAddressMapper());
        });
    }
}

public class CustomerMapper : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<CustomerViewModel, Customer>().ForMember(customer => customer.Address, expression => expression.MapFrom(viewModel => viewModel.Address));
    }
}

public class CustomerAddressMapper : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<CustomerAddressViewModel, Address>();
    }
}

Global.asax:

AutoMapperWebConfiguration.Configure();

My ViewModels is then

public class CreateAccountViewModel
{
    public CustomerViewModel Customer { get; set; }

    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    public string ConfirmPassword { get; set; }
}

public class CustomerViewModel
{
    [Required]
    [Display(Name = "Company Name")]
    public String CompanyName { get; set; }

    [Required]
    [Display(Name = "CVR")]
    public String CVR { get; set; }

    [Required]
    [Display(Name = "First name")]
    public String FirstName { get; set; }

    [Required]
    [Display(Name = "Last name")]
    public String LastName { get; set; }

    [Required]
    [Display(Name = "Phone (mobile)")]
    public String Phone { get; set; }

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

    public CustomerAddressViewModel Address { get; set; }
}

public class CustomerAddressViewModel
{
    [Required]
    [Display(Name = "Streey")]
    public String Street { get; set; }

    [Required]
    [Display(Name = "Postal code")]
    public String PostalCode { get; set; }

    [Required]
    [Display(Name = "City")]
    public String City { get; set; }

    [Required]
    [Display(Name = "Country")]
    public String Country { get; set; }
}

And finally my action, which takes the CreateAccountViewModel

//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(CreateAccountViewModel model)
{
    if (ModelState.IsValid) {
        Customer customer = Mapper.Map<Customer>(model.Customer);
        var user = new ApplicationUser() { UserName = model.UserName, Customer = customer };

        var result = UserManager.Create(user, model.Password);
        if (result.Succeeded)
        {
            await SignInAsync(user, false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            AddErrors(result);
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}
Salome answered 24/12, 2013 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.