2

Before i started i would like to say i searched and found nothing similar
in my solution i have a model that contains a list of some of my objects

public class ModelView
{
    public Owner owner = new Owner();
    public Tenant tnt = new Tenant();
}

In my view i call that class as a model which is this way

@model WebApp.Models.ModelView

<form name="export_form" action="Export" method="post">
    <table cellpadding="2" cellspacing="2" border="0">
        @if (Condition_1)
        { 
            <tr>
                <td>
                    <!-- ID -->
                </td>
                <td>
                    @Html.HiddenFor(model => model.owner.ID)
                </td>
            </tr>
            <tr>
                <td>
                    Name
                </td>
                <td>
                    @Html.EditorFor(model => model.owner.name)
                </td>
            </tr>
            <tr>
                <td>
                    Phone
                </td>
                <td>
                    @Html.CheckBoxFor(model => model.owner.is_Checked_Phone)
                </td>
            </tr>
        }
        else 
        {
            <tr>
                <td>
                    <!-- ID -->
                </td>
                <td>
                    @Html.HiddenFor(model => model.tnt.ID)
                </td>
            </tr>
            <tr>
                <td>
                    Name
                </td>
                <td>
                    @Html.EditorFor(model => model.tnt.name)
                </td>
            </tr>
            <tr>
                <td>
                    Adress
                </td>
                <td>
                    @Html.CheckBoxFor(model => model.tnt.is_Checked_Adress)
                </td>
            </tr>
        }
    </table>
    <input type="submit" name="SaveStuff" value="Save" />
    <input type="submit" name="ExportStuff" value="Export" />
</form>

In my controller i have a class that handles multiple submit buttons and depending on the button name it would redirect to a method. below is the SaveStuff method

    [HttpPost]
    [SubmitButtonClass(Name = "SaveStuff")]
    public ActionResult Save_Definition(Owner owner, Tenant tnt) 
    {
        /*
          Stuff Here
        */
    }

the problem here is i keep getting null values even thought the entities are not null. is there a reason why? no values are returned.

Update
Model A

 public partial class Owner
{
    public long ID { get; set; }
    public bool is_Checked_Name { get; set; }
    public bool is_Checked_Phone { get; set; }
}

Model B

 public partial class Tenant
{
    public long ID{ get; set; }
    public bool is_Checked_Name { get; set; }
    public bool is_Checked_Adress { get; set; }
}

these are auto generated using EF

Ranked Bronze
  • 71
  • 1
  • 9
  • The model in the view is `ModelView` so your POST method signature needs to be `public ActionResult Save_Definition(ModelView model)` to match (alternatively you can use the `Prefix` property of `BindAttribute` –  Apr 23 '16 at 03:14
  • But what you doing by have a view model that contains data models is awful practice and you view model should be a flat structure containing the properties you need in the view. –  Apr 23 '16 at 03:15
  • thats the least of his problems... – Aydin Apr 23 '16 at 03:16
  • @AydinAdn, I was writing a comment explaining why your now deleted answer was wrong :) –  Apr 23 '16 at 03:18
  • my method is public & when i return the `ModelView` it's the same issue. also that's the only practice i know for multiple data models is there better? – Ranked Bronze Apr 23 '16 at 03:20
  • No idea what you mean by _my method is public_ (I know it is but what does that have to do with your issue). And if you change the method to `ModelView model`, then one or other of those properties in your view model will be correctly bound. And yes, there is a better way, but you need to explain what `@if (Condition_1)` is and show the definitions for each model. –  Apr 23 '16 at 03:24
  • there is an attribute in the model that would show either data model A or B depending on it's value, didn't think it's importance is of matter as the issue is the same. i will update the models definition – Ranked Bronze Apr 23 '16 at 03:31
  • Your still missing some stuff from your models (your view is referring to properties `is_Checked_Phone` and `is_Checked_Adress` and you still need to explain the `if` statement in the view –  Apr 23 '16 at 03:36
  • And I have just noticed your view model has fields, not properties so the `DefaultModelBinder` cannot even set any values. –  Apr 23 '16 at 03:40
  • i updated the wrong models. basically this would export some data or save/add an update to the model. that's what the `is_checked` is for, a simple checkbox if checked the values of it's data model will be exported to a file. as for the `if` it's a switch between the `Owner` & the `Tenant` that shows `A` or `B` – Ranked Bronze Apr 23 '16 at 03:43
  • thank you. idk how this worked previously with other methods. – Ranked Bronze Apr 23 '16 at 03:50

2 Answers2

0

You have multiple issues with your code. Firstly the model in your view is ModelView and you generating form controls prefixed with that models property names, for example

<input type="checkbox" name="owner.is_Checked_Phone" ... />

which means your POST method needs to match the model in the view

public ActionResult Save_Definition(ModelView model)

The next issue is that you model only has fields, not properties with { get; set; }, so the DefaultModelBinder cannot set any values. Your view model would need properties such as public Owner owner { get; set; } and you set the value in either the controller before you pass the model to the view, or in a parameterless constructor for ModelView.

However a view model should not contain properties which are data models, but rather be a flat structure containing only the properties you need. In your case, it would be

public class ModelView
{
    public long ID { get; set; }
    [Display(Name = "Name")]
    public bool IsNameSelected { get; set; }
    [Display(Name = "Phone")]
    public bool IsPhoneSelected { get; set; }
    [Display(Name = "Address")]
    public bool IsAddressSelected { get; set; }
    // additional property to define if the form is for an Owner or Tenant
    public bool IsOwner { get; set; }
}

and in the GET method

var model = new ModelView()
{
    IsOwner = true // or false
};
return View(model);

and in the view

@model ModelView
....
@using (Html.BeginForm("Save_Definition"))
{
    @Html.HiddenFor(m => m.ID)
    @Html.HiddenFor(m => m.IsOwner)
    @Html.CheckBoxFor(m => m.IsNameSelected )
    @Html.LabelFor(m => m.IsNameSelected )
    if (Model.IsOwner)
    {
        @Html.CheckBoxFor(m => m.IsPhoneSelected)
        @Html.LabelFor(m => m.IsPhoneSelected)
    }
    else
    {
        @Html.CheckBoxFor(m => m.IsAddressSelected)
        @Html.LabelFor(m => m.IsAddressSelected)
    }
    .... // submit buttons
}

and the POST method, you can check the value of model.IsOwner to know if you have submitted an Owner or Tenant and take the appropriate action.

Side notes:

  1. Recommend you read What is ViewModel in MVC?
  2. The <table> element is for tabular data. Do not use it for layout.
  3. Your view has <form action="Export" .. > yet your POST method is named Save_Definition so unsure which method you intending to submit the form to.
Community
  • 1
  • 1
  • thank you i will try it later when i get time & read the article you provided. as for the 3rd side note `Export` is the controller name `Save_Defintion` and another method are submit methods based on what the user chooses (Save or Export) – Ranked Bronze Apr 23 '16 at 10:19
  • Then `action="Export"` would never go to your method - it would need to be `action="Export/Save_Defintion"` (always use the strongly typed helpers). And what do your mean _and another method_? Do you have some javascript modifying the value of the `action` attribute? –  Apr 23 '16 at 10:23
  • oh i see. another method is my 2nd method. i have 2 submit buttons when i looked out i saw there is 3 ways to handle it. either by doing multiple forms, using jquery (i think) or creating a class in the controller that redirects to the `actionresult` method based on the button name. i can update the second action method & the class in the controller if it helps understand what i mean. – Ranked Bronze Apr 23 '16 at 14:42
  • it's working i was just wondering i was just wondering is it good practice to declare a method in the `model` like a constructor that would get or set an `owner` or a `tenant` – Ranked Bronze Apr 23 '16 at 16:06
  • Without knowing the code your using, its hard to say. If its a view model, I would say generally its not - you would also need a parameterless constructor or an exception will be thrown when you submit, and its the controller which should be responsible for setting properties. –  Apr 24 '16 at 00:54
  • oh i didn't know that thanks again i made it work. no constructors just filling values. – Ranked Bronze Apr 24 '16 at 03:18
0

If your post controller is changing original model data, you will need to issue a ModelState.Remove("propertyname") followed by model.propertyname = "new value" and then a simple return View(model) will update the changed value on your already posted view.

Rudy Hinojosa
  • 1,448
  • 14
  • 15