Theva Deva
Theva Deva

Reputation: 63

MVC Model data is not binding

I have created form to add customer. I rendered customer page with Viewmodel. View Model class as follows,

public class CustomerViewModel
{
    public IEnumerable<MemberShipType> MemberShipTypes { get; set; }
    public Customer Customers { get; set; }
}  

public class Customer
{
    [Display(Name ="Customer ID")]
    public int CustomerId { get; set; }

    [Required(ErrorMessage = "Please enter customer name")]
    [StringLength(255)]
    [Display(Name ="Customer Name")]
    public string CustomerName { get; set; }

    public MemberShipType MemberShipType { get; set; }

    [Required(ErrorMessage = "Please select membership type")]
    [Display(Name = "Membership Type")]
    public byte MembershipTypeId { get; set; }
}

public class MemberShipType
{
    [Display(Name ="Membership Id")]
    public byte Id { get; set; }
    [Required]
    [Display(Name = "Subscription Plan")]
    public string Name { get; set; }
}

After adding that class, we have created Action to save customer form data using a single model class(Not viewModel)

I have created Customer form using Viewmodel to display with Membership type data.

UI is rendering fine with the below code. But, I am not able to get the model data in the action method.

If I directly use the viewmodel in the action data is coming fine. The problem needs to map all the view model property to a particular model.

It's required more time to map model property each time.

Can any know how to directly use entity framework add method with customer Model(Not View model)

@using (Html.BeginForm("Save", "Customer", FormMethod.Post))
{
    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(m => m.Customers.CustomerName, htmlAttributes: 
            new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(m => m.Customers.CustomerName, 
                new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(m => m.Customers.CustomerName, "", 
                new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(m => m.Customers.MembershipTypeId, htmlAttributes: 
             new { @class = "control-label col-md-2" })
            <div class="col-lg-10">

                @Html.DropDownListFor(m => m.Customers.MembershipTypeId,
                    new SelectList(Model.MemberShipTypes, "Id", "Name"), 
                    "Please Select", new {@class = "form-control"})

                @Html.ValidationMessageFor(m => m.Customers.MembershipTypeId, 
                    "", 
                    new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-lg-10 col-lg-offset-2">
                <input type="reset" value="Reset" class="btn btn-default" />
                <button type="submit" class="btn btn-primary">Save</button>    
            </div>
        </div>

    </div>
}

The below action model always return null.

        [System.Web.Mvc.HttpPost]
        public ActionResult Save(Customer customer)
        {
            if (customer.CustomerId == 0)
            { 
              _context.Customer.Add(customer);
              _context.SaveChanges();
            }
        }

I am getting a Customer model is null. If I pass customerViewModel data is coming. Can anyone know the answer on how to directly get the data in the model class?

Upvotes: 0

Views: 2198

Answers (2)

Theva Deva
Theva Deva

Reputation: 63

I got the solution for this issue. The reason for the problem is, I've created controller and Model in the same name. So, I've changed Model name with different alias in Viewmodel like below,

public class CustomerViewModel 
{ 
    public IEnumerable<MemberShipType> MemberShipTypes 
    { get; set; } 
    public ProductionCustomer productionCustomers 
    { get; set; }
}  

If we use model object in controller to Get/POST it will work even if we rendered the form with ViewModel(Multiple Model). By default mvc will identify the model to post in the form.

Upvotes: 0

kd345205
kd345205

Reputation: 319

Since you're binding the view to a model of CustomerViewModel and you're using the HTML helpers EditorFor (lambda overload), you should expect that same model in return on your POST. When you use LabelFor and EditorFor, the automatic naming will probably give you something like "Customers_CustomerName" so it can put your view model back together again.

One solution is to change your expected model on your save method to be a 'CustomerViewModel' and just use the .Customer property to get the data.

[System.Web.Mvc.HttpPost]
        public ActionResult Save(CustomerViewModel model)
        {
            if (model.Customer.CustomerId == 0)
            { 
              _context.Customer.Add(model.Customer);
              _context.SaveChanges();
            }
        }

Another option is to name your input fields manually to reflect properties of the 'Customer' model directly and it will map them into a "Customer" model for you on POST. eg Instead of @Html.LabelFor(m => m.Customers.CustomerName you'd just use @Html.EditorFor("CustomerName", Model.Customers.CustomerName)

<div class="form-group">
            @Html.LabelFor(m => m.Customers.CustomerName, htmlAttributes: 
            new { @class = "control-label col-md-2" })
            <div class="col-md-10">
 *********EDIT HERE      --> @Html.TextBox("CustomerName", Model.Customers.CustomerName
                new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(m => m.Customers.CustomerName, "", 
                new { @class = "text-danger" })
            </div>
        </div>

Upvotes: 1

Related Questions